Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24bc269e authored by Zaiyue Xue's avatar Zaiyue Xue
Browse files

Refactor BatteryChartView X-axis labels. Instead of

only timestamps, also support any string[] labels.

Bug: 236101166
Test: manual
Change-Id: I84763ccce0ee63da0b5b26e1416bf5bd5b58963d
parent 661c035a
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -588,9 +588,13 @@ public class BatteryChartPreferenceControllerV2 extends AbstractPreferenceContro
        if (mBatteryChartView == null || mBatteryHistoryKeys == null) {
            return;
        }
        final long latestTimestamp =
                mBatteryHistoryKeys[mBatteryHistoryKeys.length - 1];
        mBatteryChartView.setLatestTimestamp(latestTimestamp);
        final boolean is24HourFormat = DateFormat.is24HourFormat(mContext);
        final String[] labels = new String[mBatteryHistoryKeys.length];
        for (int i = 0; i < mBatteryHistoryKeys.length; i++) {
            labels[i] = ConvertUtils.utcToLocalTimeHour(mContext, mBatteryHistoryKeys[i],
                    is24HourFormat);
        }
        mBatteryChartView.setAxisLabels(labels);
    }

    private void addFooterPreferenceIfNeeded(boolean containAppItems) {
+55 −57
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static com.android.settings.Utils.formatPercentage;
import static java.lang.Math.round;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -29,8 +30,6 @@ import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Handler;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.HapticFeedbackConstants;
@@ -46,7 +45,6 @@ import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.Utils;

import java.time.Clock;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@@ -59,8 +57,8 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
            Arrays.asList("SwitchAccessService", "TalkBackService", "JustSpeakService");

    private static final int DEFAULT_TRAPEZOID_COUNT = 12;
    private static final int DEFAULT_TIMESTAMP_COUNT = 4;
    private static final int TIMESTAMP_GAPS_COUNT = DEFAULT_TIMESTAMP_COUNT - 1;
    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 long UPDATE_STATE_DELAYED_TIME = 500L;

@@ -87,7 +85,7 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
    @VisibleForTesting
    int mSelectedIndex = SELECTED_INDEX_INVALID;
    @VisibleForTesting
    String[] mTimestamps;
    String[] mAxisLabels;

    // Colors for drawing the trapezoid shape and dividers.
    private int mTrapezoidColor;
@@ -98,8 +96,8 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
    private final Rect mIndent = new Rect();
    private final Rect[] mPercentageBounds =
            new Rect[]{new Rect(), new Rect(), new Rect()};
    // For drawing the timestamp information.
    private final Rect[] mTimestampsBounds =
    // For drawing the axis label information.
    private final Rect[] mAxisLabelsBounds =
            new Rect[]{new Rect(), new Rect(), new Rect(), new Rect()};

    @VisibleForTesting
@@ -131,7 +129,6 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
        setSelectedIndex(SELECTED_INDEX_ALL);
        setTrapezoidCount(DEFAULT_TRAPEZOID_COUNT);
        setClickable(false);
        setLatestTimestamp(0);
    }

    /** Sets the total trapezoid count for drawing. */
@@ -199,24 +196,22 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
        requestLayout();
    }

    /** Sets the latest timestamp for drawing into x-axis information. */
    public void setLatestTimestamp(long latestTimestamp) {
        if (latestTimestamp == 0) {
            latestTimestamp = Clock.systemUTC().millis();
        }
        if (mTimestamps == null) {
            mTimestamps = new String[DEFAULT_TIMESTAMP_COUNT];
    /**
     * Sets the X-axis labels list for each level. This class will choose some labels among the
     * input list to show.
     *
     * @param labels The length of this parameter should be the same as the length of
     *               {@code levels}.
     */
    public void setAxisLabels(@NonNull String[] labels) {
        if (mAxisLabels == null) {
            mAxisLabels = new String[DEFAULT_AXIS_LABEL_COUNT];
        }
        final long timeSlotOffset =
                DateUtils.HOUR_IN_MILLIS * (/*total 24 hours*/ 24 / TIMESTAMP_GAPS_COUNT);
        final boolean is24HourFormat = DateFormat.is24HourFormat(getContext());
        for (int index = 0; index < DEFAULT_TIMESTAMP_COUNT; index++) {
            mTimestamps[index] =
                    ConvertUtils.utcToLocalTimeHour(
                            getContext(),
                            latestTimestamp - (TIMESTAMP_GAPS_COUNT - index)
                                    * timeSlotOffset,
                            is24HourFormat);
        // Current logic is always showing {@code AXIS_LABEL_GAPS_COUNT} labels.
        // TODO: Support different count of labels for different levels sizes.
        final int step = (labels.length - 1) / AXIS_LABEL_GAPS_COUNT;
        for (int index = 0; index < DEFAULT_AXIS_LABEL_COUNT; index++) {
            mAxisLabels[index] = labels[index * step];
        }
        requestLayout();
    }
@@ -235,13 +230,13 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
            mIndent.top = mPercentageBounds[0].height();
            mIndent.right = mPercentageBounds[0].width() + mTextPadding;

            if (mTimestamps != null) {
            if (mAxisLabels != null) {
                int maxHeight = 0;
                for (int index = 0; index < DEFAULT_TIMESTAMP_COUNT; index++) {
                for (int index = 0; index < DEFAULT_AXIS_LABEL_COUNT; index++) {
                    mTextPaint.getTextBounds(
                            mTimestamps[index], 0, mTimestamps[index].length(),
                            mTimestampsBounds[index]);
                    maxHeight = Math.max(maxHeight, mTimestampsBounds[index].height());
                            mAxisLabels[index], 0, mAxisLabels[index].length(),
                            mAxisLabelsBounds[index]);
                    maxHeight = Math.max(maxHeight, mAxisLabelsBounds[index].height());
                }
                mIndent.bottom = maxHeight + round(mTextPadding * 1.5f);
            }
@@ -463,47 +458,50 @@ public class BatteryChartViewV2 extends AppCompatImageView implements View.OnCli
            }
            startX = nextX;
        }
        // Draws the timestamp slot information.
        if (mTimestamps != null) {
            final float[] xOffsets = new float[DEFAULT_TIMESTAMP_COUNT];
        // Draws the axis label slot information.
        if (mAxisLabels != null) {
            final float[] xOffsets = new float[DEFAULT_AXIS_LABEL_COUNT];
            final float baselineX = mDividerWidth * .5f;
            final float offsetX = mDividerWidth + unitWidth;
            final int slotBarOffset = (/*total 12 bars*/ 12) / TIMESTAMP_GAPS_COUNT;
            for (int index = 0; index < DEFAULT_TIMESTAMP_COUNT; index++) {
            // TODO: Support different count of labels for different levels sizes.
            final int slotBarOffset = (/*total 12 bars*/ 12) / AXIS_LABEL_GAPS_COUNT;
            for (int index = 0; index < DEFAULT_AXIS_LABEL_COUNT; index++) {
                xOffsets[index] = baselineX + index * offsetX * slotBarOffset;
            }
            drawTimestamp(canvas, xOffsets);
            drawAxisLabel(canvas, xOffsets);
        }
    }

    private void drawTimestamp(Canvas canvas, float[] xOffsets) {
        // Draws the 1st timestamp info.
    private void drawAxisLabel(Canvas canvas, float[] xOffsets) {
        // Draws the 1st axis label info.
        canvas.drawText(
                mTimestamps[0],
                xOffsets[0] - mTimestampsBounds[0].left,
                getTimestampY(0), mTextPaint);
        final int latestIndex = DEFAULT_TIMESTAMP_COUNT - 1;
        // Draws the last timestamp info.
                mAxisLabels[0], xOffsets[0] - mAxisLabelsBounds[0].left, getAxisLabelY(0),
                mTextPaint);
        final int latestIndex = DEFAULT_AXIS_LABEL_COUNT - 1;
        // Draws the last axis label info.
        canvas.drawText(
                mTimestamps[latestIndex],
                xOffsets[latestIndex] - mTimestampsBounds[latestIndex].width()
                        - mTimestampsBounds[latestIndex].left,
                getTimestampY(latestIndex), mTextPaint);
        // Draws the rest of timestamp info since it is located in the center.
        for (int index = 1; index <= DEFAULT_TIMESTAMP_COUNT - 2; index++) {
                mAxisLabels[latestIndex],
                xOffsets[latestIndex]
                        - mAxisLabelsBounds[latestIndex].width()
                        - mAxisLabelsBounds[latestIndex].left,
                getAxisLabelY(latestIndex),
                mTextPaint);
        // 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++) {
            canvas.drawText(
                    mTimestamps[index],
                    mAxisLabels[index],
                    xOffsets[index]
                            - (mTimestampsBounds[index].width() - mTimestampsBounds[index].left)
                            - (mAxisLabelsBounds[index].width() - mAxisLabelsBounds[index].left)
                            * .5f,
                    getTimestampY(index), mTextPaint);

                    getAxisLabelY(index),
                    mTextPaint);
        }
    }

    private int getTimestampY(int index) {
        return getHeight() - mTimestampsBounds[index].height()
                + (mTimestampsBounds[index].height() + mTimestampsBounds[index].top)
    private int getAxisLabelY(int index) {
        return getHeight()
                - mAxisLabelsBounds[index].height()
                + (mAxisLabelsBounds[index].height() + mAxisLabelsBounds[index].top)
                + round(mTextPadding * 1.5f);
    }

+6 −4
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -58,6 +57,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

@RunWith(RobolectricTestRunner.class)
public final class BatteryChartPreferenceControllerV2Test {
@@ -94,6 +94,7 @@ public final class BatteryChartPreferenceControllerV2Test {
        MockitoAnnotations.initMocks(this);
        Locale.setDefault(new Locale("en_US"));
        org.robolectric.shadows.ShadowSettings.set24HourTimeFormat(false);
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        mFeatureFactory = FakeFeatureFactory.setupForTest();
        mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
        mContext = spy(RuntimeEnvironment.application);
@@ -588,7 +589,7 @@ public final class BatteryChartPreferenceControllerV2Test {
        mBatteryChartPreferenceController.setTimestampLabel();

        verify(mBatteryChartPreferenceController.mBatteryChartView, never())
                .setLatestTimestamp(anyLong());
                .setAxisLabels(any());
    }

    @Test
@@ -601,7 +602,7 @@ public final class BatteryChartPreferenceControllerV2Test {
        mBatteryChartPreferenceController.setTimestampLabel();

        verify(mBatteryChartPreferenceController.mBatteryChartView)
                .setLatestTimestamp(1619247636826L);
                .setAxisLabels(new String[] {"4 pm", "12 am", "7 am"});
    }

    @Test
@@ -614,7 +615,7 @@ public final class BatteryChartPreferenceControllerV2Test {
        mBatteryChartPreferenceController.setTimestampLabel();

        verify(mBatteryChartPreferenceController.mBatteryChartView)
                .setLatestTimestamp(anyLong());
                .setAxisLabels(new String[] {"12 am"});
    }

    @Test
@@ -684,6 +685,7 @@ public final class BatteryChartPreferenceControllerV2Test {

    private void setUpBatteryHistoryKeys() {
        mBatteryChartPreferenceController.mBatteryHistoryKeys =
                // "2021-04-23 16:53:06 UTC", "1970-01-01 00:00:00 UTC", "2021-04-23 07:00:36 UTC"
                new long[]{1619196786769L, 0L, 1619247636826L};
        ConvertUtils.utcToLocalTimeHour(
                mContext, /*timestamp=*/ 0, /*is24HourFormat=*/ false);