diff options
6 files changed, 145 insertions, 41 deletions
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index a4bc235aaa7a..efc4baa6ab5a 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -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> diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index 1150ac10c063..d55158118b3f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -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); } diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java index 92db50878a70..327e470e7d22 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryUtils.java @@ -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; + } } diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java index 22726549ce05..5ed59996bee3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java @@ -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); + } } + diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java index 2e7905f2e1e4..cbc382b6b920 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java @@ -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"); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 1ec86aea49d8..1963d641702a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -194,20 +194,20 @@ public class KeyguardIndicationController { private boolean mOrganizationOwnedDevice; // these all assume the device is plugged in (wired/wireless/docked) AND chargingOrFull: - private boolean mPowerPluggedIn; - private boolean mPowerPluggedInWired; - private boolean mPowerPluggedInWireless; - private boolean mPowerPluggedInDock; + protected boolean mPowerPluggedIn; + protected boolean mPowerPluggedInWired; + protected boolean mPowerPluggedInWireless; + protected boolean mPowerPluggedInDock; private boolean mPowerCharged; private boolean mBatteryDefender; private boolean mEnableBatteryDefender; private boolean mIncompatibleCharger; - private int mChargingSpeed; + protected int mChargingSpeed; private int mChargingWattage; private int mBatteryLevel; private boolean mBatteryPresent = true; - private long mChargingTimeRemaining; + protected long mChargingTimeRemaining; private Pair<String, BiometricSourceType> mBiometricErrorMessageToShowOnScreenOn; private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow; private final FaceHelpMessageDeferral mFaceAcquiredMessageDeferral; @@ -1052,20 +1052,24 @@ public class KeyguardIndicationController { * Assumption: device is charging */ protected String computePowerIndication() { - int chargingId; if (mBatteryDefender) { - chargingId = R.string.keyguard_plugged_in_charging_limited; String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); - return mContext.getResources().getString(chargingId, percentage); + return mContext.getResources().getString( + R.string.keyguard_plugged_in_charging_limited, percentage); } else if (mPowerPluggedIn && mIncompatibleCharger) { - chargingId = R.string.keyguard_plugged_in_incompatible_charger; String percentage = NumberFormat.getPercentInstance().format(mBatteryLevel / 100f); - return mContext.getResources().getString(chargingId, percentage); + return mContext.getResources().getString( + R.string.keyguard_plugged_in_incompatible_charger, percentage); } else if (mPowerCharged) { return mContext.getResources().getString(R.string.keyguard_charged); } + return computePowerChargingStringIndication(); + } + + protected String computePowerChargingStringIndication() { final boolean hasChargingTime = mChargingTimeRemaining > 0; + int chargingId; if (mPowerPluggedInWired) { switch (mChargingSpeed) { case BatteryStatus.CHARGING_FAST: |