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

Commit 4da9a6a9 authored by YK Hung's avatar YK Hung Committed by Android (Google) Code Review
Browse files

Merge "Implement the method for time short string" into 24D1-dev

parents c2652890 3c94f844
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