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

Commit 3c94f844 authored by pajacechen's avatar pajacechen Committed by Cherrypicker Worker
Browse files

Implement the method for time short string

- Add new charging string
- Implement the method to convert remaining time milliseconds to short
  string format, e.g. "1:30PM"
- Increase some class variable to protect in
  KeyguardIndicationController

Test: Unit Test and Manual test
Bug: 328546483
Flag: NA
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:71628170ad71416d36508d9b815b6f53d214ab4e)
Merged-In: I52788abd4f09bb32259b00f915dbe704ac0442af
Change-Id: I52788abd4f09bb32259b00f915dbe704ac0442af
parent bb338d7a
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -1131,6 +1131,16 @@
    <!-- [CHAR_LIMIT=80] Label for battery charging future pause -->
    <string name="power_charging_future_paused"><xliff:g id="level">%1$s</xliff:g> - Charging</string>

    <!-- [CHAR_LIMIT=40] Label for battery level when fast charging with duration. -->
    <string name="power_fast_charging_duration_v2"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="status">%2$s</xliff:g> - Full by <xliff:g id="time">%3$s</xliff:g></string>
    <!-- [CHAR_LIMIT=40] Label for battery level when non-fast charging with duration. -->
    <string name="power_charging_duration_v2"><xliff:g id="level">%1$s</xliff:g> - Fully charged by <xliff:g id="time">%2$s</xliff:g></string>

    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging. -->
    <string name="power_remaining_charging_duration_only_v2">Fully charged by <xliff:g id="time">%1$s</xliff:g></string>
    <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging. -->
    <string name="power_remaining_fast_charging_duration_only_v2">Full by <xliff:g id="time">%1$s</xliff:g></string>

    <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
    <string name="battery_info_status_unknown">Unknown</string>
    <!-- [CHAR_LIMIT=20] Battery use screen.  Battery status shown in chart label when charging from an unknown source.  -->
@@ -1154,6 +1164,11 @@
    <!-- [CHAR_LIMIT=None] Battery Info screen. Value for a status item. A state which device charging on hold -->
    <string name="battery_info_status_charging_on_hold">Charging on hold</string>

    <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging isn't fast. -->
    <string name="battery_info_status_charging_v2">Charging</string>
    <!-- [CHAR_LIMIT=20] Battery use screen. Battery status shown in chart label when charging speed is fast. -->
    <string name="battery_info_status_charging_fast_v2">Fast charging</string>

    <!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
    <string name="disabled_by_admin_summary_text">Controlled by admin</string>

+42 −8
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ import com.android.launcher3.icons.IconFactory;
import com.android.launcher3.util.UserIconInfo;
import com.android.settingslib.drawable.UserIconDrawable;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.settingslib.fuelgauge.BatteryUtils;
import com.android.settingslib.utils.BuildCompatUtils;

import java.text.NumberFormat;
@@ -259,25 +260,23 @@ public class Utils {
        } else {
            if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
                if (compactStatus) {
                    statusString = res.getString(R.string.battery_info_status_charging);
                    statusString = getRegularChargingStatusString(res);
                } else if (batteryStatus.isPluggedInWired()) {
                    switch (batteryStatus.getChargingSpeed(context)) {
                        case BatteryStatus.CHARGING_FAST:
                            statusString =
                                    res.getString(R.string.battery_info_status_charging_fast);
                            statusString = getFastChargingStatusString(res);
                            break;
                        case BatteryStatus.CHARGING_SLOWLY:
                            statusString =
                                    res.getString(R.string.battery_info_status_charging_slow);
                            statusString = getSlowChargingStatusString(res);
                            break;
                        default:
                            statusString = res.getString(R.string.battery_info_status_charging);
                            statusString = getRegularChargingStatusString(res);
                            break;
                    }
                } else if (batteryStatus.isPluggedInDock()) {
                    statusString = res.getString(R.string.battery_info_status_charging_dock);
                    statusString = getDockChargingStatusString(res);
                } else {
                    statusString = res.getString(R.string.battery_info_status_charging_wireless);
                    statusString = getWirelessChargingStatusString(res);
                }
            } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
                statusString = res.getString(R.string.battery_info_status_discharging);
@@ -289,6 +288,41 @@ public class Utils {
        return statusString;
    }

    private static String getFastChargingStatusString(Resources res) {
        return res.getString(
                BatteryUtils.isChargingStringV2Enabled()
                        ? R.string.battery_info_status_charging_fast_v2
                        : R.string.battery_info_status_charging_fast);
    }

    private static String getSlowChargingStatusString(Resources res) {
        return res.getString(
                BatteryUtils.isChargingStringV2Enabled()
                        ? R.string.battery_info_status_charging_v2
                        : R.string.battery_info_status_charging_slow);
    }

    private static String getRegularChargingStatusString(Resources res) {
        return res.getString(
                BatteryUtils.isChargingStringV2Enabled()
                        ? R.string.battery_info_status_charging_v2
                        : R.string.battery_info_status_charging);
    }

    private static String getWirelessChargingStatusString(Resources res) {
        return res.getString(
                BatteryUtils.isChargingStringV2Enabled()
                        ? R.string.battery_info_status_charging_v2
                        : R.string.battery_info_status_charging_wireless);
    }

    private static String getDockChargingStatusString(Resources res) {
        return res.getString(
                BatteryUtils.isChargingStringV2Enabled()
                        ? R.string.battery_info_status_charging_v2
                        : R.string.battery_info_status_charging_dock);
    }

    public static ColorStateList getColorAccent(Context context) {
        return getColorAttr(context, android.R.attr.colorAccent);
    }
+28 −1
Original line number Diff line number Diff line
@@ -21,11 +21,14 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.provider.Settings;
import android.os.SystemProperties;
import android.os.UserManager;
import android.provider.Settings;
import android.util.ArraySet;
import android.view.accessibility.AccessibilityManager;

import androidx.annotation.VisibleForTesting;

import java.util.List;

public final class BatteryUtils {
@@ -33,6 +36,9 @@ public final class BatteryUtils {
    /** The key to get the time to full from Settings.Global */
    public static final String GLOBAL_TIME_TO_FULL_MILLIS = "time_to_full_millis";

    /** The system property key to check whether the charging string v2 is enabled or not. */
    public static final String PROPERTY_CHARGING_STRING_V2_KEY = "charging_string.apply_v2";

    /** Gets the latest sticky battery intent from the Android system. */
    public static Intent getBatteryIntent(Context context) {
        return context.registerReceiver(
@@ -75,4 +81,25 @@ public final class BatteryUtils {
        final UserManager userManager = context.getSystemService(UserManager.class);
        return userManager.isManagedProfile() && !userManager.isSystemUser();
    }

    private static Boolean sChargingStringV2Enabled = null;

    /** Returns {@code true} if the charging string v2 is enabled. */
    public static boolean isChargingStringV2Enabled() {
        if (sChargingStringV2Enabled == null) {
            sChargingStringV2Enabled =
                    SystemProperties.getBoolean(PROPERTY_CHARGING_STRING_V2_KEY, false);
        }
        return sChargingStringV2Enabled;
    }


    /** Used to override the system property to enable or reset for charging string V2. */
    @VisibleForTesting
    public static void setChargingStringV2Enabled(Boolean enabled) {
        SystemProperties.set(
                BatteryUtils.PROPERTY_CHARGING_STRING_V2_KEY,
                enabled == null ? "" : String.valueOf(enabled));
        BatteryUtils.sChargingStringV2Enabled = enabled;
    }
}
+16 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

/** Utility class for keeping power related strings consistent**/
/** Utility class for keeping power related strings consistent. **/
public class PowerUtil {

    private static final long SEVEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(7);
@@ -221,4 +221,19 @@ public class PowerUtil {
            return time - remainder + multiple;
        }
    }

    /** Gets the rounded target time string in a short format. */
    public static String getTargetTimeShortString(
            Context context, long targetTimeOffsetMs, long currentTimeMs) {
        final long roundedTimeOfDayMs =
                roundTimeToNearestThreshold(
                        currentTimeMs + targetTimeOffsetMs, FIFTEEN_MINUTES_MILLIS);

        // convert the time to a properly formatted string.
        String skeleton = android.text.format.DateFormat.getTimeFormatString(context);
        DateFormat fmt = DateFormat.getInstanceForSkeleton(skeleton);
        Date date = Date.from(Instant.ofEpochMilli(roundedTimeOfDayMs));
        return fmt.format(date);
    }
}
+29 −20
Original line number Diff line number Diff line
@@ -20,30 +20,24 @@ import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.spy;

import android.app.AlarmManager;
import android.content.Context;

import androidx.test.core.app.ApplicationProvider;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

import java.time.Duration;
import java.time.Instant;
import java.util.Locale;
import java.util.regex.Pattern;

@RunWith(RobolectricTestRunner.class)
public class PowerUtilTest {
    private static final String TEST_BATTERY_LEVEL_10 = "10%";
    private static final long TEN_SEC_MILLIS = Duration.ofSeconds(10).toMillis();
    private static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis();
    private static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis();
    private static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis();
    private static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis();
    private static final long TEN_HOURS_MILLIS = Duration.ofHours(10).toMillis();
    private static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis();
    private static final String NORMAL_CASE_EXPECTED_PREFIX = "Should last until about";
    private static final String ENHANCED_SUFFIX = " based on your usage";
    private static final String BATTERY_RUN_OUT_PREFIX = "Battery may run out by";
    // matches a time (ex: '1:15 PM', '2 AM', '23:00')
    private static final String TIME_OF_DAY_REGEX = " (\\d)+:?(\\d)* ((AM)*)|((PM)*)";
@@ -55,29 +49,31 @@ public class PowerUtilTest {
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mContext = spy(RuntimeEnvironment.application);
        mContext = spy(ApplicationProvider.getApplicationContext());
    }

    @Test
    public void getBatteryTipStringFormatted_moreThanOneDay_usesCorrectString() {
        String info = PowerUtil.getBatteryTipStringFormatted(mContext,
                THREE_DAYS_MILLIS);
        var threeDayMillis = Duration.ofDays(3).toMillis();

        String batteryTipString = PowerUtil.getBatteryTipStringFormatted(mContext, threeDayMillis);

        assertThat(info).isEqualTo("More than 3 days left");
        assertThat(batteryTipString).isEqualTo("More than 3 days left");
    }

    @Test
    public void getBatteryTipStringFormatted_lessThanOneDay_usesCorrectString() {
        String info = PowerUtil.getBatteryTipStringFormatted(mContext,
                SEVENTEEN_MIN_MILLIS);
        var drainTimeMs = Duration.ofMinutes(17).toMillis();

        String batteryTipString = PowerUtil.getBatteryTipStringFormatted(mContext, drainTimeMs);

        // ex: Battery may run out by 1:15 PM
        assertThat(info).containsMatch(Pattern.compile(
                BATTERY_RUN_OUT_PREFIX + TIME_OF_DAY_REGEX));
        assertThat(batteryTipString)
                .containsMatch(Pattern.compile(BATTERY_RUN_OUT_PREFIX + TIME_OF_DAY_REGEX));
    }

    @Test
    public void testRoundToNearestThreshold_roundsCorrectly() {
    public void roundTimeToNearestThreshold_roundsCorrectly() {
        // test some pretty normal values
        assertThat(PowerUtil.roundTimeToNearestThreshold(1200, 1000)).isEqualTo(1000);
        assertThat(PowerUtil.roundTimeToNearestThreshold(800, 1000)).isEqualTo(1000);
@@ -89,4 +85,17 @@ public class PowerUtilTest {
        assertThat(PowerUtil.roundTimeToNearestThreshold(-120, 100)).isEqualTo(100);
        assertThat(PowerUtil.roundTimeToNearestThreshold(-200, -75)).isEqualTo(225);
    }

    @Test
    public void getTargetTimeShortString_returnsTimeShortString() {
        mContext.getSystemService(AlarmManager.class).setTimeZone("UTC");
        mContext.getResources().getConfiguration().setLocale(Locale.US);
        var currentTimeMs = Instant.parse("2024-06-06T15:00:00Z").toEpochMilli();
        var remainingTimeMs = Duration.ofMinutes(30).toMillis();

        var actualTimeString =
                PowerUtil.getTargetTimeShortString(mContext, remainingTimeMs, currentTimeMs);

        assertThat(actualTimeString).isEqualTo("3:30 PM");
    }
}
Loading