Merge "Implement general projection curve support for UsageGraph." into oc-dr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
bf9cb113c1
@@ -62,7 +62,7 @@ public class ChartDataUsagePreference extends Preference {
|
|||||||
|
|
||||||
int top = getTop();
|
int top = getTop();
|
||||||
chart.clearPaths();
|
chart.clearPaths();
|
||||||
chart.configureGraph(toInt(mEnd - mStart), top, false, false);
|
chart.configureGraph(toInt(mEnd - mStart), top);
|
||||||
calcPoints(chart);
|
calcPoints(chart);
|
||||||
chart.setBottomLabels(new CharSequence[] {
|
chart.setBottomLabels(new CharSequence[] {
|
||||||
Utils.formatDateRange(getContext(), mStart, mStart),
|
Utils.formatDateRange(getContext(), mStart, mStart),
|
||||||
|
@@ -55,18 +55,23 @@ public class BatteryInfo {
|
|||||||
public void bindHistory(final UsageView view, BatteryDataParser... parsers) {
|
public void bindHistory(final UsageView view, BatteryDataParser... parsers) {
|
||||||
BatteryDataParser parser = new BatteryDataParser() {
|
BatteryDataParser parser = new BatteryDataParser() {
|
||||||
SparseIntArray points = new SparseIntArray();
|
SparseIntArray points = new SparseIntArray();
|
||||||
|
int lastTime = -1;
|
||||||
|
byte lastLevel;
|
||||||
|
int maxTime;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onParsingStarted(long startTime, long endTime) {
|
public void onParsingStarted(long startTime, long endTime) {
|
||||||
timePeriod = endTime - startTime - remainingTimeUs / 1000;
|
this.maxTime = (int) (endTime - startTime);
|
||||||
|
timePeriod = maxTime - (remainingTimeUs / 1000);
|
||||||
view.clearPaths();
|
view.clearPaths();
|
||||||
view.configureGraph((int) (endTime - startTime), 100, remainingTimeUs != 0,
|
view.configureGraph(maxTime, 100);
|
||||||
mCharging);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDataPoint(long time, HistoryItem record) {
|
public void onDataPoint(long time, HistoryItem record) {
|
||||||
points.put((int) time, record.batteryLevel);
|
lastTime = (int) time;
|
||||||
|
lastLevel = record.batteryLevel;
|
||||||
|
points.put(lastTime, lastLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -79,8 +84,13 @@ public class BatteryInfo {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onParsingDone() {
|
public void onParsingDone() {
|
||||||
if (points.size() > 1) {
|
onDataGap();
|
||||||
view.addPath(points);
|
|
||||||
|
// Add linear projection
|
||||||
|
if (lastTime >= 0 && remainingTimeUs != 0) {
|
||||||
|
points.put(lastTime, lastLevel);
|
||||||
|
points.put(maxTime, mCharging ? 100 : 0);
|
||||||
|
view.addProjectedPath(points);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -32,6 +32,7 @@ import android.util.AttributeSet;
|
|||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.android.settingslib.R;
|
import com.android.settingslib.R;
|
||||||
|
|
||||||
public class UsageGraph extends View {
|
public class UsageGraph extends View {
|
||||||
@@ -52,11 +53,14 @@ public class UsageGraph extends View {
|
|||||||
private final SparseIntArray mPaths = new SparseIntArray();
|
private final SparseIntArray mPaths = new SparseIntArray();
|
||||||
// Paths in local coordinates for drawing.
|
// Paths in local coordinates for drawing.
|
||||||
private final SparseIntArray mLocalPaths = new SparseIntArray();
|
private final SparseIntArray mLocalPaths = new SparseIntArray();
|
||||||
private final int mCornerRadius;
|
|
||||||
|
|
||||||
|
// Paths for projection in coordinates they are passed in.
|
||||||
|
private final SparseIntArray mProjectedPaths = new SparseIntArray();
|
||||||
|
// Paths for projection in local coordinates for drawing.
|
||||||
|
private final SparseIntArray mLocalProjectedPaths = new SparseIntArray();
|
||||||
|
|
||||||
|
private final int mCornerRadius;
|
||||||
private int mAccentColor;
|
private int mAccentColor;
|
||||||
private boolean mShowProjection;
|
|
||||||
private boolean mProjectUp;
|
|
||||||
|
|
||||||
private float mMaxX = 100;
|
private float mMaxX = 100;
|
||||||
private float mMaxY = 100;
|
private float mMaxY = 100;
|
||||||
@@ -86,7 +90,7 @@ public class UsageGraph extends View {
|
|||||||
float dots = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_size);
|
float dots = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_size);
|
||||||
float interval = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_interval);
|
float interval = resources.getDimensionPixelSize(R.dimen.usage_graph_dot_interval);
|
||||||
mDottedPaint.setStrokeWidth(dots * 3);
|
mDottedPaint.setStrokeWidth(dots * 3);
|
||||||
mDottedPaint.setPathEffect(new DashPathEffect(new float[] {dots, interval}, 0));
|
mDottedPaint.setPathEffect(new DashPathEffect(new float[]{dots, interval}, 0));
|
||||||
mDottedPaint.setColor(context.getColor(R.color.usage_graph_dots));
|
mDottedPaint.setColor(context.getColor(R.color.usage_graph_dots));
|
||||||
|
|
||||||
TypedValue v = new TypedValue();
|
TypedValue v = new TypedValue();
|
||||||
@@ -98,6 +102,9 @@ public class UsageGraph extends View {
|
|||||||
|
|
||||||
void clearPaths() {
|
void clearPaths() {
|
||||||
mPaths.clear();
|
mPaths.clear();
|
||||||
|
mLocalPaths.clear();
|
||||||
|
mProjectedPaths.clear();
|
||||||
|
mLocalProjectedPaths.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMax(int maxX, int maxY) {
|
void setMax(int maxX, int maxY) {
|
||||||
@@ -115,11 +122,21 @@ public class UsageGraph extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addPath(SparseIntArray points) {
|
public void addPath(SparseIntArray points) {
|
||||||
for (int i = 0; i < points.size(); i++) {
|
addPathAndUpdate(points, mPaths, mLocalPaths);
|
||||||
mPaths.put(points.keyAt(i), points.valueAt(i));
|
}
|
||||||
|
|
||||||
|
public void addProjectedPath(SparseIntArray points) {
|
||||||
|
addPathAndUpdate(points, mProjectedPaths, mLocalProjectedPaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPathAndUpdate(SparseIntArray points, SparseIntArray paths,
|
||||||
|
SparseIntArray localPaths) {
|
||||||
|
for (int i = 0, size = points.size(); i < size; i++) {
|
||||||
|
paths.put(points.keyAt(i), points.valueAt(i));
|
||||||
}
|
}
|
||||||
mPaths.put(points.keyAt(points.size() - 1) + 1, PATH_DELIM);
|
// Add a delimiting value immediately after the last point.
|
||||||
calculateLocalPaths();
|
paths.put(points.keyAt(points.size() - 1) + 1, PATH_DELIM);
|
||||||
|
calculateLocalPaths(paths, localPaths);
|
||||||
postInvalidate();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,48 +147,45 @@ public class UsageGraph extends View {
|
|||||||
postInvalidate();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setShowProjection(boolean showProjection, boolean projectUp) {
|
|
||||||
mShowProjection = showProjection;
|
|
||||||
mProjectUp = projectUp;
|
|
||||||
postInvalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
super.onSizeChanged(w, h, oldw, oldh);
|
||||||
updateGradient();
|
updateGradient();
|
||||||
calculateLocalPaths();
|
calculateLocalPaths(mPaths, mLocalPaths);
|
||||||
|
calculateLocalPaths(mProjectedPaths, mLocalProjectedPaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void calculateLocalPaths() {
|
private void calculateLocalPaths(SparseIntArray paths, SparseIntArray localPaths) {
|
||||||
if (getWidth() == 0) return;
|
if (getWidth() == 0) {
|
||||||
mLocalPaths.clear();
|
return;
|
||||||
|
}
|
||||||
|
localPaths.clear();
|
||||||
int pendingXLoc = 0;
|
int pendingXLoc = 0;
|
||||||
int pendingYLoc = PATH_DELIM;
|
int pendingYLoc = PATH_DELIM;
|
||||||
for (int i = 0; i < mPaths.size(); i++) {
|
for (int i = 0; i < paths.size(); i++) {
|
||||||
int x = mPaths.keyAt(i);
|
int x = paths.keyAt(i);
|
||||||
int y = mPaths.valueAt(i);
|
int y = paths.valueAt(i);
|
||||||
if (y == PATH_DELIM) {
|
if (y == PATH_DELIM) {
|
||||||
if (i == mPaths.size() - 1 && pendingYLoc != PATH_DELIM) {
|
if (i == paths.size() - 1 && pendingYLoc != PATH_DELIM) {
|
||||||
// Connect to the end of the graph.
|
// Connect to the end of the graph.
|
||||||
mLocalPaths.put(pendingXLoc, pendingYLoc);
|
localPaths.put(pendingXLoc, pendingYLoc);
|
||||||
}
|
}
|
||||||
// Clear out any pending points.
|
// Clear out any pending points.
|
||||||
pendingYLoc = PATH_DELIM;
|
pendingYLoc = PATH_DELIM;
|
||||||
mLocalPaths.put(pendingXLoc + 1, PATH_DELIM);
|
localPaths.put(pendingXLoc + 1, PATH_DELIM);
|
||||||
} else {
|
} else {
|
||||||
final int lx = getX(x);
|
final int lx = getX(x);
|
||||||
final int ly = getY(y);
|
final int ly = getY(y);
|
||||||
pendingXLoc = lx;
|
pendingXLoc = lx;
|
||||||
if (mLocalPaths.size() > 0) {
|
if (localPaths.size() > 0) {
|
||||||
int lastX = mLocalPaths.keyAt(mLocalPaths.size() - 1);
|
int lastX = localPaths.keyAt(localPaths.size() - 1);
|
||||||
int lastY = mLocalPaths.valueAt(mLocalPaths.size() - 1);
|
int lastY = localPaths.valueAt(localPaths.size() - 1);
|
||||||
if (lastY != PATH_DELIM && !hasDiff(lastX, lx) && !hasDiff(lastY, ly)) {
|
if (lastY != PATH_DELIM && !hasDiff(lastX, lx) && !hasDiff(lastY, ly)) {
|
||||||
pendingYLoc = ly;
|
pendingYLoc = ly;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLocalPaths.put(lx, ly);
|
localPaths.put(lx, ly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,8 +203,9 @@ public class UsageGraph extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateGradient() {
|
private void updateGradient() {
|
||||||
mFillPaint.setShader(new LinearGradient(0, 0, 0, getHeight(),
|
mFillPaint.setShader(
|
||||||
getColor(mAccentColor, .2f), 0, TileMode.CLAMP));
|
new LinearGradient(0, 0, 0, getHeight(), getColor(mAccentColor, .2f), 0,
|
||||||
|
TileMode.CLAMP));
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getColor(int color, float alphaScale) {
|
private int getColor(int color, float alphaScale) {
|
||||||
@@ -207,62 +222,54 @@ public class UsageGraph extends View {
|
|||||||
mMiddleDividerTint);
|
mMiddleDividerTint);
|
||||||
drawDivider(canvas.getHeight() - mDividerSize, canvas, -1);
|
drawDivider(canvas.getHeight() - mDividerSize, canvas, -1);
|
||||||
|
|
||||||
if (mLocalPaths.size() == 0) {
|
if (mLocalPaths.size() == 0 && mProjectedPaths.size() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mShowProjection) {
|
drawLinePath(canvas, mLocalProjectedPaths, mDottedPaint);
|
||||||
drawProjection(canvas);
|
drawFilledPath(canvas, mLocalPaths, mFillPaint);
|
||||||
|
drawLinePath(canvas, mLocalPaths, mLinePaint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void drawLinePath(Canvas canvas, SparseIntArray localPaths, Paint paint) {
|
||||||
|
if (localPaths.size() == 0) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
drawFilledPath(canvas);
|
|
||||||
drawLinePath(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawProjection(Canvas canvas) {
|
|
||||||
mPath.reset();
|
mPath.reset();
|
||||||
int x = mLocalPaths.keyAt(mLocalPaths.size() - 2);
|
mPath.moveTo(localPaths.keyAt(0), localPaths.valueAt(0));
|
||||||
int y = mLocalPaths.valueAt(mLocalPaths.size() - 2);
|
for (int i = 1; i < localPaths.size(); i++) {
|
||||||
mPath.moveTo(x, y);
|
int x = localPaths.keyAt(i);
|
||||||
mPath.lineTo(canvas.getWidth(), mProjectUp ? 0 : canvas.getHeight());
|
int y = localPaths.valueAt(i);
|
||||||
canvas.drawPath(mPath, mDottedPaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawLinePath(Canvas canvas) {
|
|
||||||
mPath.reset();
|
|
||||||
mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0));
|
|
||||||
for (int i = 1; i < mLocalPaths.size(); i++) {
|
|
||||||
int x = mLocalPaths.keyAt(i);
|
|
||||||
int y = mLocalPaths.valueAt(i);
|
|
||||||
if (y == PATH_DELIM) {
|
if (y == PATH_DELIM) {
|
||||||
if (++i < mLocalPaths.size()) {
|
if (++i < localPaths.size()) {
|
||||||
mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i));
|
mPath.moveTo(localPaths.keyAt(i), localPaths.valueAt(i));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mPath.lineTo(x, y);
|
mPath.lineTo(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
canvas.drawPath(mPath, mLinePaint);
|
canvas.drawPath(mPath, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawFilledPath(Canvas canvas) {
|
private void drawFilledPath(Canvas canvas, SparseIntArray localPaths, Paint paint) {
|
||||||
mPath.reset();
|
mPath.reset();
|
||||||
float lastStartX = mLocalPaths.keyAt(0);
|
float lastStartX = localPaths.keyAt(0);
|
||||||
mPath.moveTo(mLocalPaths.keyAt(0), mLocalPaths.valueAt(0));
|
mPath.moveTo(localPaths.keyAt(0), localPaths.valueAt(0));
|
||||||
for (int i = 1; i < mLocalPaths.size(); i++) {
|
for (int i = 1; i < localPaths.size(); i++) {
|
||||||
int x = mLocalPaths.keyAt(i);
|
int x = localPaths.keyAt(i);
|
||||||
int y = mLocalPaths.valueAt(i);
|
int y = localPaths.valueAt(i);
|
||||||
if (y == PATH_DELIM) {
|
if (y == PATH_DELIM) {
|
||||||
mPath.lineTo(mLocalPaths.keyAt(i - 1), getHeight());
|
mPath.lineTo(localPaths.keyAt(i - 1), getHeight());
|
||||||
mPath.lineTo(lastStartX, getHeight());
|
mPath.lineTo(lastStartX, getHeight());
|
||||||
mPath.close();
|
mPath.close();
|
||||||
if (++i < mLocalPaths.size()) {
|
if (++i < localPaths.size()) {
|
||||||
lastStartX = mLocalPaths.keyAt(i);
|
lastStartX = localPaths.keyAt(i);
|
||||||
mPath.moveTo(mLocalPaths.keyAt(i), mLocalPaths.valueAt(i));
|
mPath.moveTo(localPaths.keyAt(i), localPaths.valueAt(i));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mPath.lineTo(x, y);
|
mPath.lineTo(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
canvas.drawPath(mPath, mFillPaint);
|
canvas.drawPath(mPath, paint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawDivider(int y, Canvas canvas, int tintColor) {
|
private void drawDivider(int y, Canvas canvas, int tintColor) {
|
||||||
|
@@ -91,9 +91,12 @@ public class UsageView extends FrameLayout {
|
|||||||
mUsageGraph.addPath(points);
|
mUsageGraph.addPath(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void configureGraph(int maxX, int maxY, boolean showProjection, boolean projectUp) {
|
public void addProjectedPath(SparseIntArray points) {
|
||||||
|
mUsageGraph.addProjectedPath(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configureGraph(int maxX, int maxY) {
|
||||||
mUsageGraph.setMax(maxX, maxY);
|
mUsageGraph.setMax(maxX, maxY);
|
||||||
mUsageGraph.setShowProjection(showProjection, projectUp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAccentColor(int color) {
|
public void setAccentColor(int color) {
|
||||||
|
Reference in New Issue
Block a user