diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java index ff8ff583034..a2cb9ae30cb 100644 --- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java @@ -33,6 +33,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.Utils; @@ -60,6 +61,7 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController private Activity mActivity; private PreferenceFragmentCompat mHost; private Lifecycle mLifecycle; + private BatteryTip mBatteryTip; private final PowerManager mPowerManager; public BatteryHeaderPreferenceController(Context context, String key) { @@ -109,8 +111,26 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController if (BatteryUtils.isBatteryDefenderOn(info)) { return null; } else if (info.remainingLabel == null) { + // Present status independently if no remaining time return info.statusLabel; + } else if (info.statusLabel != null && !info.discharging) { + // Charging state + return mContext.getString( + R.string.battery_state_and_duration, info.statusLabel, info.remainingLabel); + } else if (mPowerManager.isPowerSaveMode()) { + // Power save mode is on + final String powerSaverOn = mContext.getString( + R.string.battery_tip_early_heads_up_done_title); + return mContext.getString( + R.string.battery_state_and_duration, powerSaverOn, info.remainingLabel); + } else if (mBatteryTip != null + && mBatteryTip.getType() == BatteryTip.TipType.LOW_BATTERY) { + // Low battery state + final String lowBattery = mContext.getString(R.string.low_battery_summary); + return mContext.getString( + R.string.battery_state_and_duration, lowBattery, info.remainingLabel); } else { + // Discharging state return info.remainingLabel; } } @@ -140,6 +160,17 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController mBatteryUsageProgressBarPref.setPercent(batteryLevel, BATTERY_MAX_LEVEL); } + /** + * Update summary when battery tips changed. + */ + public void updateHeaderByBatteryTips(BatteryTip batteryTip, BatteryInfo batteryInfo) { + mBatteryTip = batteryTip; + + if (mBatteryTip != null && batteryInfo != null) { + updateHeaderPreference(batteryInfo); + } + } + private CharSequence formatBatteryPercentageText(int batteryLevel) { return TextUtils.expandTemplate(mContext.getText(R.string.battery_header_title_alternate), NumberFormat.getIntegerInstance().format(batteryLevel)); diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index 9e619973122..7dfca22f9c4 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -94,6 +94,8 @@ public class PowerUsageSummary extends PowerUsageBase implements @Override public void onLoadFinished(Loader loader, BatteryInfo batteryInfo) { mBatteryHeaderPreferenceController.updateHeaderPreference(batteryInfo); + mBatteryHeaderPreferenceController.updateHeaderByBatteryTips( + mBatteryTipPreferenceController.getCurrentBatteryTip(), batteryInfo); mBatteryInfo = batteryInfo; } @@ -115,6 +117,8 @@ public class PowerUsageSummary extends PowerUsageBase implements public void onLoadFinished(Loader> loader, List data) { mBatteryTipPreferenceController.updateBatteryTips(data); + mBatteryHeaderPreferenceController.updateHeaderByBatteryTips( + mBatteryTipPreferenceController.getCurrentBatteryTip(), mBatteryInfo); } @Override diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java index 00b1e874d33..c6afefe9961 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java @@ -16,6 +16,7 @@ package com.android.settings.fuelgauge.batterytip; +import android.annotation.Nullable; import android.content.Context; import android.os.Bundle; @@ -162,6 +163,19 @@ public class BatteryTipPreferenceController extends BasePreferenceController { return mNeedUpdate; } + /** + * @return current battery tips, null if unavailable. + */ + @Nullable + public BatteryTip getCurrentBatteryTip() { + if (mBatteryTips == null) { + return null; + } + + return mBatteryTips.stream().anyMatch(BatteryTip::isVisible) + ? mBatteryTips.stream().filter(BatteryTip::isVisible).findFirst().get() : null; + } + /** * Listener to give the control back to target fragment */ diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java index ad10fa8c975..038798adee5 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java @@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.app.Activity; @@ -44,6 +45,9 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip; +import com.android.settings.fuelgauge.batterytip.tips.SmartBatteryTip; import com.android.settings.testutils.shadow.ShadowEntityHeaderController; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.widget.EntityHeaderController; @@ -58,7 +62,9 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowPowerManager; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowEntityHeaderController.class, ShadowUtils.class}) @@ -84,7 +90,7 @@ public class BatteryHeaderPreferenceControllerTest { private UsageProgressBarPreference mBatteryUsageProgressBarPref; private BatteryHeaderPreferenceController mController; private Context mContext; - private PowerManager mPowerManager; + private ShadowPowerManager mShadowPowerManager; private Intent mBatteryIntent; private LifecycleOwner mLifecycleOwner; private Lifecycle mLifecycle; @@ -109,7 +115,7 @@ public class BatteryHeaderPreferenceControllerTest { mBatteryInfo.batteryLevel = BATTERY_LEVEL; - mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mShadowPowerManager = Shadows.shadowOf(mContext.getSystemService(PowerManager.class)); mController = spy(new BatteryHeaderPreferenceController(mContext, PREF_KEY)); mLifecycle.addObserver(mController); @@ -144,9 +150,7 @@ public class BatteryHeaderPreferenceControllerTest { @Test public void updatePreference_updateBatteryInfo() { - mBatteryInfo.remainingLabel = TIME_LEFT; - mBatteryInfo.batteryLevel = BATTERY_LEVEL; - mBatteryInfo.discharging = true; + setChargingState(/* isDischarging */ true); mController.updateHeaderPreference(mBatteryInfo); @@ -165,6 +169,68 @@ public class BatteryHeaderPreferenceControllerTest { verify(mBatteryUsageProgressBarPref).setBottomSummary(BATTERY_STATUS); } + @Test + public void updatePreference_charging_showFullText() { + setChargingState(/* isDischarging */ false); + + mController.updateHeaderPreference(mBatteryInfo); + + final String expectedResult = BATTERY_STATUS + " • " + TIME_LEFT; + verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedResult); + } + + @Test + public void updatePreference_powerSaverOn_showPowerSaverOn() { + setChargingState(/* isDischarging */ true); + mShadowPowerManager.setIsPowerSaveMode(true); + + mController.updateHeaderPreference(mBatteryInfo); + + final String expectedResult = "Battery Saver is on • " + TIME_LEFT; + verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedResult); + } + + @Test + public void updateHeaderByBatteryTips_lowBatteryTip_showLowBattery() { + setChargingState(/* isDischarging */ true); + BatteryTip lowBatteryTip = new LowBatteryTip( + BatteryTip.StateType.NEW, /* powerSaveModeOn */false); + + mController.updateHeaderByBatteryTips(lowBatteryTip, mBatteryInfo); + + final String expectedResult = "Low battery • " + TIME_LEFT; + verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedResult); + } + + @Test + public void updateHeaderByBatteryTips_notLowBatteryTip_showRemainingLabel() { + setChargingState(/* isDischarging */ true); + BatteryTip lowBatteryTip = new SmartBatteryTip(BatteryTip.StateType.NEW); + + mController.updateHeaderByBatteryTips(lowBatteryTip, mBatteryInfo); + + verify(mBatteryUsageProgressBarPref).setBottomSummary(mBatteryInfo.remainingLabel); + } + + @Test + public void updateHeaderByBatteryTips_noTip_noAction() { + setChargingState(/* isDischarging */ true); + + mController.updateHeaderByBatteryTips(null, mBatteryInfo); + + verifyZeroInteractions(mBatteryUsageProgressBarPref); + } + + @Test + public void updateHeaderByBatteryTips_noBatteryInfo_noAction() { + BatteryTip lowBatteryTip = new LowBatteryTip( + BatteryTip.StateType.NEW, /* powerSaveModeOn */false); + + mController.updateHeaderByBatteryTips(lowBatteryTip, null); + + verifyZeroInteractions(mBatteryUsageProgressBarPref); + } + @Test public void updatePreference_isOverheat_showEmptyText() { mBatteryInfo.isOverheated = true; @@ -203,4 +269,10 @@ public class BatteryHeaderPreferenceControllerTest { return TextUtils.expandTemplate(mContext.getText(R.string.battery_header_title_alternate), NumberFormat.getIntegerInstance().format(BATTERY_LEVEL)); } + + private void setChargingState(boolean isDischarging) { + mBatteryInfo.remainingLabel = TIME_LEFT; + mBatteryInfo.statusLabel = BATTERY_STATUS; + mBatteryInfo.discharging = isDischarging; + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java index e9192889cd9..dbde3a7ed28 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java @@ -127,6 +127,25 @@ public class BatteryTipPreferenceControllerTest { BatteryTip.StateType.NEW); } + @Test + public void testGetCurrentBatteryTip_noTips_isNull() { + assertThat(mBatteryTipPreferenceController.getCurrentBatteryTip()).isNull(); + } + + @Test + public void testGetCurrentBatteryTip_tipsInvisible_isNull() { + mBatteryTipPreferenceController.updateBatteryTips(mNewBatteryTips); + assertThat(mBatteryTipPreferenceController.getCurrentBatteryTip()).isNull(); + } + + @Test + public void testGetCurrentBatteryTip_tipsVisible_returnTips() { + mBatteryTipPreferenceController.updateBatteryTips(mOldBatteryTips); + + assertThat(mBatteryTipPreferenceController.getCurrentBatteryTip().getType()).isEqualTo( + BatteryTip.TipType.SUMMARY); + } + @Test public void testSaveAndRestore() { mBatteryTipPreferenceController.updateBatteryTips(mOldBatteryTips);