Improve X axis labels in battery chart (2)
Support showing different numbers of labels for different count of trapezoids. screen_record: https://drive.google.com/file/d/1CIgppQllHlKC3BGG7hBvOjGDGVOs6OYC/view?usp=sharing&resourcekey=0-mbofu5KOO2dqCwL7K0zakg Test: manual Bug: 239491373 Bug: 236101166 Change-Id: I865dae760b491bdd7c93bbd29fd7dbc33204a60a
This commit is contained in:
@@ -47,8 +47,11 @@ import com.android.settings.overlay.FeatureFactory;
|
|||||||
import com.android.settingslib.Utils;
|
import com.android.settingslib.Utils;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/** A widget component to draw chart graph. */
|
/** A widget component to draw chart graph. */
|
||||||
public class BatteryChartViewV2 extends AppCompatImageView implements View.OnClickListener,
|
public class BatteryChartViewV2 extends AppCompatImageView implements View.OnClickListener,
|
||||||
@@ -57,10 +60,10 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
private static final List<String> ACCESSIBILITY_SERVICE_NAMES =
|
private static final List<String> ACCESSIBILITY_SERVICE_NAMES =
|
||||||
Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService");
|
Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService");
|
||||||
|
|
||||||
private static final int DEFAULT_AXIS_LABEL_COUNT = 4;
|
|
||||||
private static final int AXIS_LABEL_GAPS_COUNT = DEFAULT_AXIS_LABEL_COUNT - 1;
|
|
||||||
private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5");
|
private static final int DIVIDER_COLOR = Color.parseColor("#CDCCC5");
|
||||||
private static final long UPDATE_STATE_DELAYED_TIME = 500L;
|
private static final long UPDATE_STATE_DELAYED_TIME = 500L;
|
||||||
|
private static final Map<Integer, Integer[]> MODEL_SIZE_TO_LABEL_INDEXES_MAP =
|
||||||
|
buildModelSizeToLabelIndexesMap();
|
||||||
|
|
||||||
/** A callback listener for selected group index is updated. */
|
/** A callback listener for selected group index is updated. */
|
||||||
public interface OnSelectListener {
|
public interface OnSelectListener {
|
||||||
@@ -76,11 +79,10 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
private float mTrapezoidHOffset;
|
private float mTrapezoidHOffset;
|
||||||
private boolean mIsSlotsClickabled;
|
private boolean mIsSlotsClickabled;
|
||||||
private String[] mPercentages = getPercentages();
|
private String[] mPercentages = getPercentages();
|
||||||
|
private Integer[] mLabelsIndexes;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
|
int mHoveredIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
|
||||||
@VisibleForTesting
|
|
||||||
String[] mAxisLabels;
|
|
||||||
|
|
||||||
// Colors for drawing the trapezoid shape and dividers.
|
// Colors for drawing the trapezoid shape and dividers.
|
||||||
private int mTrapezoidColor;
|
private int mTrapezoidColor;
|
||||||
@@ -92,8 +94,7 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
private final Rect[] mPercentageBounds =
|
private final Rect[] mPercentageBounds =
|
||||||
new Rect[]{new Rect(), new Rect(), new Rect()};
|
new Rect[]{new Rect(), new Rect(), new Rect()};
|
||||||
// For drawing the axis label information.
|
// For drawing the axis label information.
|
||||||
private final Rect[] mAxisLabelsBounds =
|
private final Rect[] mAxisLabelsBounds = initializeAxisLabelsBounds();
|
||||||
new Rect[]{new Rect(), new Rect(), new Rect(), new Rect()};
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Handler mHandler = new Handler();
|
Handler mHandler = new Handler();
|
||||||
@@ -137,9 +138,8 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
Log.d(TAG, String.format("setViewModel(): size: %d, selectedIndex: %d.",
|
Log.d(TAG, String.format("setViewModel(): size: %d, selectedIndex: %d.",
|
||||||
viewModel.size(), viewModel.selectedIndex()));
|
viewModel.size(), viewModel.selectedIndex()));
|
||||||
mViewModel = viewModel;
|
mViewModel = viewModel;
|
||||||
|
mLabelsIndexes = MODEL_SIZE_TO_LABEL_INDEXES_MAP.get(mViewModel.size());
|
||||||
initializeTrapezoidSlots(viewModel.size() - 1);
|
initializeTrapezoidSlots(viewModel.size() - 1);
|
||||||
initializeAxisLabels(viewModel.texts());
|
|
||||||
setClickable(hasAnyValidTrapezoid(viewModel));
|
setClickable(hasAnyValidTrapezoid(viewModel));
|
||||||
requestLayout();
|
requestLayout();
|
||||||
}
|
}
|
||||||
@@ -176,12 +176,11 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
mIndent.top = mPercentageBounds[0].height();
|
mIndent.top = mPercentageBounds[0].height();
|
||||||
mIndent.right = mPercentageBounds[0].width() + mTextPadding;
|
mIndent.right = mPercentageBounds[0].width() + mTextPadding;
|
||||||
|
|
||||||
if (mAxisLabels != null) {
|
if (mViewModel != null) {
|
||||||
int maxHeight = 0;
|
int maxHeight = 0;
|
||||||
for (int index = 0; index < DEFAULT_AXIS_LABEL_COUNT; index++) {
|
for (int index = 0; index < mLabelsIndexes.length; index++) {
|
||||||
mTextPaint.getTextBounds(
|
final String text = getAxisLabelText(index);
|
||||||
mAxisLabels[index], 0, mAxisLabels[index].length(),
|
mTextPaint.getTextBounds(text, 0, text.length(), mAxisLabelsBounds[index]);
|
||||||
mAxisLabelsBounds[index]);
|
|
||||||
maxHeight = Math.max(maxHeight, mAxisLabelsBounds[index].height());
|
maxHeight = Math.max(maxHeight, mAxisLabelsBounds[index].height());
|
||||||
}
|
}
|
||||||
mIndent.bottom = maxHeight + round(mTextPadding * 1.5f);
|
mIndent.bottom = maxHeight + round(mTextPadding * 1.5f);
|
||||||
@@ -333,21 +332,6 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the displayed X-axis labels list selected from the model all texts list.
|
|
||||||
*/
|
|
||||||
private void initializeAxisLabels(@NonNull List<String> allTexts) {
|
|
||||||
if (mAxisLabels == null) {
|
|
||||||
mAxisLabels = new String[DEFAULT_AXIS_LABEL_COUNT];
|
|
||||||
}
|
|
||||||
// Current logic is always showing {@code AXIS_LABEL_GAPS_COUNT} labels.
|
|
||||||
// TODO: Support different count of labels for different levels sizes.
|
|
||||||
final int step = (allTexts.size() - 1) / AXIS_LABEL_GAPS_COUNT;
|
|
||||||
for (int index = 0; index < DEFAULT_AXIS_LABEL_COUNT; index++) {
|
|
||||||
mAxisLabels[index] = allTexts.get(index * step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeColors(Context context) {
|
private void initializeColors(Context context) {
|
||||||
setBackgroundColor(Color.TRANSPARENT);
|
setBackgroundColor(Color.TRANSPARENT);
|
||||||
mTrapezoidSolidColor = Utils.getColorAccentDefaultColor(context);
|
mTrapezoidSolidColor = Utils.getColorAccentDefaultColor(context);
|
||||||
@@ -432,14 +416,12 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
startX = nextX;
|
startX = nextX;
|
||||||
}
|
}
|
||||||
// Draws the axis label slot information.
|
// Draws the axis label slot information.
|
||||||
if (mAxisLabels != null) {
|
if (mViewModel != null) {
|
||||||
final float[] xOffsets = new float[DEFAULT_AXIS_LABEL_COUNT];
|
final float[] xOffsets = new float[mLabelsIndexes.length];
|
||||||
final float baselineX = mDividerWidth * .5f;
|
final float baselineX = mDividerWidth * .5f;
|
||||||
final float offsetX = mDividerWidth + unitWidth;
|
final float offsetX = mDividerWidth + unitWidth;
|
||||||
// TODO: Support different count of labels for different levels sizes.
|
for (int index = 0; index < mLabelsIndexes.length; index++) {
|
||||||
final int slotBarOffset = (/*total 12 bars*/ 12) / AXIS_LABEL_GAPS_COUNT;
|
xOffsets[index] = baselineX + mLabelsIndexes[index] * offsetX;
|
||||||
for (int index = 0; index < DEFAULT_AXIS_LABEL_COUNT; index++) {
|
|
||||||
xOffsets[index] = baselineX + index * offsetX * slotBarOffset;
|
|
||||||
}
|
}
|
||||||
switch (mViewModel.axisLabelPosition()) {
|
switch (mViewModel.axisLabelPosition()) {
|
||||||
case CENTER_OF_TRAPEZOIDS:
|
case CENTER_OF_TRAPEZOIDS:
|
||||||
@@ -456,21 +438,21 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
private void drawAxisLabelsBetweenTrapezoids(Canvas canvas, float[] xOffsets) {
|
private void drawAxisLabelsBetweenTrapezoids(Canvas canvas, float[] xOffsets) {
|
||||||
// Draws the 1st axis label info.
|
// Draws the 1st axis label info.
|
||||||
canvas.drawText(
|
canvas.drawText(
|
||||||
mAxisLabels[0], xOffsets[0] - mAxisLabelsBounds[0].left, getAxisLabelY(0),
|
getAxisLabelText(0), xOffsets[0] - mAxisLabelsBounds[0].left, getAxisLabelY(0),
|
||||||
mTextPaint);
|
mTextPaint);
|
||||||
final int latestIndex = DEFAULT_AXIS_LABEL_COUNT - 1;
|
final int latestIndex = mLabelsIndexes.length - 1;
|
||||||
// Draws the last axis label info.
|
// Draws the last axis label info.
|
||||||
canvas.drawText(
|
canvas.drawText(
|
||||||
mAxisLabels[latestIndex],
|
getAxisLabelText(latestIndex),
|
||||||
xOffsets[latestIndex]
|
xOffsets[latestIndex]
|
||||||
- mAxisLabelsBounds[latestIndex].width()
|
- mAxisLabelsBounds[latestIndex].width()
|
||||||
- mAxisLabelsBounds[latestIndex].left,
|
- mAxisLabelsBounds[latestIndex].left,
|
||||||
getAxisLabelY(latestIndex),
|
getAxisLabelY(latestIndex),
|
||||||
mTextPaint);
|
mTextPaint);
|
||||||
// Draws the rest of axis label info since it is located in the center.
|
// Draws the rest of axis label info since it is located in the center.
|
||||||
for (int index = 1; index <= DEFAULT_AXIS_LABEL_COUNT - 2; index++) {
|
for (int index = 1; index <= mLabelsIndexes.length - 2; index++) {
|
||||||
canvas.drawText(
|
canvas.drawText(
|
||||||
mAxisLabels[index],
|
getAxisLabelText(index),
|
||||||
xOffsets[index]
|
xOffsets[index]
|
||||||
- (mAxisLabelsBounds[index].width() - mAxisLabelsBounds[index].left)
|
- (mAxisLabelsBounds[index].width() - mAxisLabelsBounds[index].left)
|
||||||
* .5f,
|
* .5f,
|
||||||
@@ -481,9 +463,9 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
|
|
||||||
private void drawAxisLabelsCenterOfTrapezoids(
|
private void drawAxisLabelsCenterOfTrapezoids(
|
||||||
Canvas canvas, float[] xOffsets, float unitWidth) {
|
Canvas canvas, float[] xOffsets, float unitWidth) {
|
||||||
for (int index = 0; index < DEFAULT_AXIS_LABEL_COUNT - 1; index++) {
|
for (int index = 0; index < mLabelsIndexes.length - 1; index++) {
|
||||||
canvas.drawText(
|
canvas.drawText(
|
||||||
mAxisLabels[index],
|
getAxisLabelText(index),
|
||||||
xOffsets[index] + (unitWidth - (mAxisLabelsBounds[index].width()
|
xOffsets[index] + (unitWidth - (mAxisLabelsBounds[index].width()
|
||||||
- mAxisLabelsBounds[index].left)) * .5f,
|
- mAxisLabelsBounds[index].left)) * .5f,
|
||||||
getAxisLabelY(index),
|
getAxisLabelY(index),
|
||||||
@@ -574,6 +556,10 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
return BatteryChartViewModel.SELECTED_INDEX_INVALID;
|
return BatteryChartViewModel.SELECTED_INDEX_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getAxisLabelText(int labelIndex) {
|
||||||
|
return mViewModel.texts().get(mLabelsIndexes[labelIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isTrapezoidValid(
|
private static boolean isTrapezoidValid(
|
||||||
@NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
|
@NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
|
||||||
return viewModel.levels().get(trapezoidIndex) != null
|
return viewModel.levels().get(trapezoidIndex) != null
|
||||||
@@ -627,6 +613,33 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Map<Integer, Integer[]> buildModelSizeToLabelIndexesMap() {
|
||||||
|
final Map<Integer, Integer[]> result = new HashMap<>();
|
||||||
|
result.put(2, new Integer[]{0, 1});
|
||||||
|
result.put(3, new Integer[]{0, 1, 2});
|
||||||
|
result.put(4, new Integer[]{0, 1, 2, 3});
|
||||||
|
result.put(5, new Integer[]{0, 1, 2, 3, 4});
|
||||||
|
result.put(6, new Integer[]{0, 1, 2, 3, 4, 5});
|
||||||
|
result.put(7, new Integer[]{0, 1, 2, 3, 4, 5, 6});
|
||||||
|
result.put(8, new Integer[]{0, 1, 2, 3, 4, 5, 6, 7});
|
||||||
|
result.put(9, new Integer[]{0, 2, 4, 6, 8});
|
||||||
|
result.put(10, new Integer[]{0, 3, 6, 9});
|
||||||
|
result.put(11, new Integer[]{0, 5, 10});
|
||||||
|
result.put(12, new Integer[]{0, 4, 7, 11});
|
||||||
|
result.put(13, new Integer[]{0, 4, 8, 12});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rect[] initializeAxisLabelsBounds() {
|
||||||
|
final int maxLabelsLength = MODEL_SIZE_TO_LABEL_INDEXES_MAP.values().stream().max(
|
||||||
|
Comparator.comparingInt(indexes -> indexes.length)).get().length;
|
||||||
|
final Rect[] bounds = new Rect[maxLabelsLength];
|
||||||
|
for (int i = 0; i < maxLabelsLength; i++) {
|
||||||
|
bounds[i] = new Rect();
|
||||||
|
}
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
// A container class for each trapezoid left and right location.
|
// A container class for each trapezoid left and right location.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final class TrapezoidSlot {
|
static final class TrapezoidSlot {
|
||||||
|
Reference in New Issue
Block a user