diff --git a/res/values/strings.xml b/res/values/strings.xml index 138db6a548c..ff221824111 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7193,6 +7193,8 @@ + + diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java index 2041543a1fb..71e65bfdd6b 100644 --- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.BatteryManager; import android.os.PowerManager; import android.util.Log; @@ -39,6 +40,7 @@ import java.lang.annotation.RetentionPolicy; * 1. Battery level(e.g. 100%->99%) * 2. Battery status(e.g. plugged->unplugged) * 3. Battery saver(e.g. off->on) + * 4. Battery health(e.g. good->overheat) */ public class BatteryBroadcastReceiver extends BroadcastReceiver { @@ -49,6 +51,7 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver { * Battery level(e.g. 100%->99%) * Battery status(e.g. plugged->unplugged) * Battery saver(e.g. off->on) + * Battery health(e.g. good->overheat) */ public interface OnBatteryChangedListener { void onBatteryChanged(@BatteryUpdateType int type); @@ -59,19 +62,23 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver { BatteryUpdateType.BATTERY_LEVEL, BatteryUpdateType.BATTERY_SAVER, BatteryUpdateType.BATTERY_STATUS, + BatteryUpdateType.BATTERY_HEALTH, BatteryUpdateType.BATTERY_NOT_PRESENT}) public @interface BatteryUpdateType { int MANUAL = 0; int BATTERY_LEVEL = 1; int BATTERY_SAVER = 2; int BATTERY_STATUS = 3; - int BATTERY_NOT_PRESENT = 4; + int BATTERY_HEALTH = 4; + int BATTERY_NOT_PRESENT = 5; } @VisibleForTesting String mBatteryLevel; @VisibleForTesting String mBatteryStatus; + @VisibleForTesting + int mBatteryHealth; private OnBatteryChangedListener mBatteryListener; private Context mContext; @@ -106,11 +113,15 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver { if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { final String batteryLevel = Utils.getBatteryPercentage(intent); final String batteryStatus = Utils.getBatteryStatus(mContext, intent); + final int batteryHealth = intent.getIntExtra( + BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN); if (!Utils.isBatteryPresent(intent)) { Log.w(TAG, "Problem reading the battery meter."); mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT); } else if (forceUpdate) { mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL); + } else if (batteryHealth != mBatteryHealth) { + mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH); } else if(!batteryLevel.equals(mBatteryLevel)) { mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL); } else if (!batteryStatus.equals(mBatteryStatus)) { @@ -118,6 +129,7 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver { } mBatteryLevel = batteryLevel; mBatteryStatus = batteryStatus; + mBatteryHealth = batteryHealth; } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) { mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER); } diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java index 7b910a16cb2..906644482c6 100644 --- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java @@ -124,7 +124,9 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController public void updateHeaderPreference(BatteryInfo info) { mBatteryPercentText.setText(formatBatteryPercentageText(info.batteryLevel)); if (!mBatteryStatusFeatureProvider.triggerBatteryStatusUpdate(this, info)) { - if (info.remainingLabel == null) { + if (BatteryUtils.isBatteryDefenderOn(info)) { + mSummary1.setText(null); + } else if (info.remainingLabel == null) { mSummary1.setText(info.statusLabel); } else { mSummary1.setText(info.remainingLabel); diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java index 1935c35218c..49bdcbb6f05 100644 --- a/src/com/android/settings/fuelgauge/BatteryInfo.java +++ b/src/com/android/settings/fuelgauge/BatteryInfo.java @@ -45,6 +45,7 @@ public class BatteryInfo { public CharSequence remainingLabel; public int batteryLevel; public boolean discharging = true; + public boolean isOverheated; public long remainingTimeUs = 0; public long averageTimeToDischarge = EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN; public String batteryPercentString; @@ -232,6 +233,9 @@ public class BatteryInfo { info.batteryPercentString = Utils.formatPercentage(info.batteryLevel); info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; info.averageTimeToDischarge = estimate.getAverageDischargeTime(); + info.isOverheated = batteryBroadcast.getIntExtra( + BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN) + == BatteryManager.BATTERY_HEALTH_OVERHEAT; info.statusLabel = Utils.getBatteryStatus(context, batteryBroadcast); if (!info.mCharging) { @@ -251,7 +255,12 @@ public class BatteryInfo { BatteryManager.BATTERY_STATUS_UNKNOWN); info.discharging = false; info.suggestionLabel = null; - if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) { + if (info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL) { + info.remainingLabel = null; + int chargingLimitedResId = R.string.power_charging_limited; + info.chargeLabel = + context.getString(chargingLimitedResId, info.batteryPercentString); + } else if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) { info.remainingTimeUs = chargeTime; CharSequence timeString = StringUtil.formatElapsedTime(context, PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */); diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 03387f9ef80..3fc9c5e632d 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -403,6 +403,13 @@ public class BatteryUtils { Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms"); } + /** + * Return {@code true} if battery is overheated and charging. + */ + public static boolean isBatteryDefenderOn(BatteryInfo batteryInfo) { + return batteryInfo.isOverheated && !batteryInfo.discharging; + } + /** * Find package uid from package name * diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java index 8d6e07dc010..0c916b2d4a9 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java @@ -23,6 +23,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.os.BatteryStatsHelper; import com.android.settings.fuelgauge.BatteryInfo; import com.android.settings.fuelgauge.BatteryUtils; +import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector; import com.android.settings.fuelgauge.batterytip.detectors.EarlyWarningDetector; import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector; import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector; @@ -72,6 +73,7 @@ public class BatteryTipLoader extends AsyncLoaderCompat> { batteryInfo.discharging).detect()); tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect()); tips.add(new EarlyWarningDetector(policy, context).detect()); + tips.add(new BatteryDefenderDetector(batteryInfo).detect()); tips.add(new SummaryDetector(policy, batteryInfo.averageTimeToDischarge).detect()); // Disable this feature now since it introduces false positive cases. We will try to improve // it in the future. diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java index ed06cce59d1..9ef1070852a 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java @@ -29,6 +29,7 @@ import androidx.annotation.NonNull; import com.android.internal.util.CollectionUtils; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; +import com.android.settings.fuelgauge.batterytip.actions.BatteryDefenderAction; import com.android.settings.fuelgauge.batterytip.actions.BatterySaverAction; import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction; import com.android.settings.fuelgauge.batterytip.actions.OpenBatterySaverAction; @@ -111,6 +112,8 @@ public class BatteryTipUtils { } case BatteryTip.TipType.REMOVE_APP_RESTRICTION: return new UnrestrictAppAction(settingsActivity, (UnrestrictAppTip) batteryTip); + case BatteryTip.TipType.BATTERY_DEFENDER: + return new BatteryDefenderAction(settingsActivity); default: return null; } diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java new file mode 100644 index 00000000000..b8f54832b7c --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.fuelgauge.batterytip.actions; + +import android.content.Intent; + +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settingslib.HelpUtils; + +/** + * Action to open the Support Center article + */ +public class BatteryDefenderAction extends BatteryTipAction { + private SettingsActivity mSettingsActivity; + + public BatteryDefenderAction(SettingsActivity settingsActivity) { + super(settingsActivity.getApplicationContext()); + mSettingsActivity = settingsActivity; + } + + /** + * Handle the action when user clicks positive button + */ + @Override + public void handlePositiveAction(int metricsKey) { + final Intent intent = HelpUtils.getHelpIntent( + mContext, + mContext.getString(R.string.help_url_battery_defender), + getClass().getName()); + if (intent != null) { + mSettingsActivity.startActivityForResult(intent, 0); + } + // TODO(b/173985153): Add logging enums for Battery Defender. + } +} diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java new file mode 100644 index 00000000000..86744f56987 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.fuelgauge.batterytip.detectors; + +import com.android.settings.fuelgauge.BatteryInfo; +import com.android.settings.fuelgauge.BatteryUtils; +import com.android.settings.fuelgauge.batterytip.tips.BatteryDefenderTip; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; + +/** + * Detect whether the battery is overheated + */ +public class BatteryDefenderDetector implements BatteryTipDetector { + private BatteryInfo mBatteryInfo; + + public BatteryDefenderDetector(BatteryInfo batteryInfo) { + mBatteryInfo = batteryInfo; + } + + @Override + public BatteryTip detect() { + final int state = + BatteryUtils.isBatteryDefenderOn(mBatteryInfo) + ? BatteryTip.StateType.NEW + : BatteryTip.StateType.INVISIBLE; + return new BatteryDefenderTip(state); + } +} diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java new file mode 100644 index 00000000000..cd23e50e21d --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.fuelgauge.batterytip.tips; + +import android.content.Context; +import android.os.Parcel; + +import com.android.settings.R; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; + +/** + * Tip to show current battery is overheated + */ +public class BatteryDefenderTip extends BatteryTip { + + public BatteryDefenderTip(@StateType int state) { + super(TipType.BATTERY_DEFENDER, state, false /* showDialog */); + } + + private BatteryDefenderTip(Parcel in) { + super(in); + } + + @Override + public CharSequence getTitle(Context context) { + return context.getString(R.string.battery_tip_limited_temporarily_title); + } + + @Override + public CharSequence getSummary(Context context) { + return context.getString(R.string.battery_tip_limited_temporarily_summary); + } + + @Override + public int getIconId() { + return R.drawable.ic_battery_status_good_24dp; + } + + @Override + public void updateState(BatteryTip tip) { + mState = tip.mState; + } + + @Override + public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) { + // TODO(b/173985153): Add logging enums for Battery Defender. + } + + public static final Creator CREATOR = new Creator() { + public BatteryTip createFromParcel(Parcel in) { + return new BatteryDefenderTip(in); + } + + public BatteryTip[] newArray(int size) { + return new BatteryDefenderTip[size]; + } + }; + +} diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java index ebc493967e4..13015a7795b 100644 --- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java +++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java @@ -17,7 +17,6 @@ package com.android.settings.fuelgauge.batterytip.tips; import android.content.Context; -import android.content.res.ColorStateList; import android.os.Parcel; import android.os.Parcelable; import android.util.SparseIntArray; @@ -58,7 +57,8 @@ public abstract class BatteryTip implements Comparable, Parcelable { TipType.APP_RESTRICTION, TipType.REDUCED_BATTERY, TipType.LOW_BATTERY, - TipType.REMOVE_APP_RESTRICTION}) + TipType.REMOVE_APP_RESTRICTION, + TipType.BATTERY_DEFENDER}) public @interface TipType { int SMART_BATTERY_MANAGER = 0; int APP_RESTRICTION = 1; @@ -68,20 +68,22 @@ public abstract class BatteryTip implements Comparable, Parcelable { int LOW_BATTERY = 5; int SUMMARY = 6; int REMOVE_APP_RESTRICTION = 7; + int BATTERY_DEFENDER = 8; } @VisibleForTesting static final SparseIntArray TIP_ORDER; static { TIP_ORDER = new SparseIntArray(); - TIP_ORDER.append(TipType.APP_RESTRICTION, 0); - TIP_ORDER.append(TipType.BATTERY_SAVER, 1); - TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 2); - TIP_ORDER.append(TipType.LOW_BATTERY, 3); - TIP_ORDER.append(TipType.SUMMARY, 4); - TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 5); - TIP_ORDER.append(TipType.REDUCED_BATTERY, 6); - TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 7); + TIP_ORDER.append(TipType.BATTERY_DEFENDER, 0); + TIP_ORDER.append(TipType.APP_RESTRICTION, 1); + TIP_ORDER.append(TipType.BATTERY_SAVER, 2); + TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 3); + TIP_ORDER.append(TipType.LOW_BATTERY, 4); + TIP_ORDER.append(TipType.SUMMARY, 5); + TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 6); + TIP_ORDER.append(TipType.REDUCED_BATTERY, 7); + TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 8); } private static final String KEY_PREFIX = "key_battery_tip"; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java index 742daf2df79..a072988df4c 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java @@ -66,6 +66,7 @@ public class BatteryBroadcastReceiverTest { mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext); mBatteryBroadcastReceiver.mBatteryLevel = BATTERY_INIT_LEVEL; mBatteryBroadcastReceiver.mBatteryStatus = BATTERY_INIT_STATUS; + mBatteryBroadcastReceiver.mBatteryHealth = BatteryManager.BATTERY_HEALTH_UNKNOWN; mBatteryBroadcastReceiver.setBatteryChangedListener(mBatteryListener); mChargingIntent = new Intent(Intent.ACTION_BATTERY_CHANGED); @@ -90,6 +91,21 @@ public class BatteryBroadcastReceiverTest { verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL); } + @Test + @Config(shadows = { + BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, + BatteryFixSliceTest.ShadowBatteryTipLoader.class + }) + public void testOnReceive_batteryHealthChanged_dataUpdated() { + mChargingIntent + .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT); + mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent); + + assertThat(mBatteryBroadcastReceiver.mBatteryHealth) + .isEqualTo(BatteryManager.BATTERY_HEALTH_OVERHEAT); + verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH); + } + @Test @Config(shadows = { BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, @@ -131,6 +147,8 @@ public class BatteryBroadcastReceiverTest { assertThat(mBatteryBroadcastReceiver.mBatteryLevel).isEqualTo(batteryLevel); assertThat(mBatteryBroadcastReceiver.mBatteryStatus).isEqualTo(batteryStatus); + assertThat(mBatteryBroadcastReceiver.mBatteryHealth) + .isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN); verify(mBatteryListener, never()).onBatteryChanged(anyInt()); } @@ -149,6 +167,8 @@ public class BatteryBroadcastReceiverTest { .isEqualTo(Utils.getBatteryPercentage(mChargingIntent)); assertThat(mBatteryBroadcastReceiver.mBatteryStatus) .isEqualTo(Utils.getBatteryStatus(mContext, mChargingIntent)); + assertThat(mBatteryBroadcastReceiver.mBatteryHealth) + .isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN); // 2 times because register will force update the battery verify(mBatteryListener, times(2)).onBatteryChanged(BatteryUpdateType.MANUAL); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java index a6cf653314c..ac3c8f9cd5b 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java @@ -175,6 +175,15 @@ public class BatteryHeaderPreferenceControllerTest { assertThat(mSummary.getText()).isEqualTo(BATTERY_STATUS); } + @Test + public void updatePreference_isOverheat_showEmptyText() { + mBatteryInfo.isOverheated = true; + + mController.updateHeaderPreference(mBatteryInfo); + + assertThat(mSummary.getText().toString().isEmpty()).isTrue(); + } + @Test public void onStart_shouldStyleActionBar() { when(mEntityHeaderController.setRecyclerView(nullable(RecyclerView.class), eq(mLifecycle))) diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java index 3cbc58afdf8..d0af982ac3a 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java @@ -246,6 +246,22 @@ public class BatteryInfoTest { assertThat(info.chargeLabel).isEqualTo("100%"); } + @Test + public void testGetBatteryInfo_chargingWithOverheated_updateChargeLabel() { + doReturn(TEST_CHARGE_TIME_REMAINING) + .when(mBatteryStats) + .computeChargeTimeRemaining(anyLong()); + mChargingBatteryBroadcast + .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT); + + BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast, + mBatteryStats, DUMMY_ESTIMATE, SystemClock.elapsedRealtime() * 1000, + false /* shortString */); + + assertThat(info.isOverheated).isTrue(); + assertThat(info.chargeLabel).isEqualTo("50% - Battery limited temporarily"); + } + // Make our battery stats return a sequence of battery events. private void mockBatteryStatsHistory() { // Mock out new data every time start...Locked is called. diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index 0faddc3f6f3..5d985fd33a8 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -144,6 +144,8 @@ public class BatteryUtilsTest { @Mock private BatterySipper mIdleBatterySipper; @Mock + private BatteryInfo mBatteryInfo; + @Mock private Bundle mBundle; @Mock private UserManager mUserManager; @@ -754,4 +756,36 @@ public class BatteryUtilsTest { assertThat(estimate.isBasedOnUsage()).isTrue(); assertThat(estimate.getAverageDischargeTime()).isEqualTo(1000); } + + @Test + public void testIsBatteryDefenderOn_isOverheatedAndIsCharging_returnTrue() { + mBatteryInfo.isOverheated = true; + mBatteryInfo.discharging = false; + + assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isTrue(); + } + + @Test + public void testIsBatteryDefenderOn_isOverheatedAndDischarging_returnFalse() { + mBatteryInfo.isOverheated = true; + mBatteryInfo.discharging = true; + + assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse(); + } + + @Test + public void testIsBatteryDefenderOn_notOverheatedAndDischarging_returnFalse() { + mBatteryInfo.isOverheated = false; + mBatteryInfo.discharging = true; + + assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse(); + } + + @Test + public void testIsBatteryDefenderOn_notOverheatedAndIsCharging_returnFalse() { + mBatteryInfo.isOverheated = false; + mBatteryInfo.discharging = false; + + assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse(); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java index 116033b47f5..8cc17d8d98f 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java @@ -50,6 +50,7 @@ import java.util.List; public class BatteryTipLoaderTest { private static final int[] TIP_ORDER = { + BatteryTip.TipType.BATTERY_DEFENDER, BatteryTip.TipType.BATTERY_SAVER, BatteryTip.TipType.HIGH_DEVICE_USAGE, BatteryTip.TipType.LOW_BATTERY, diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java index 275bfe02787..619978897fc 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java @@ -23,10 +23,12 @@ import static org.mockito.Mockito.when; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; +import com.android.settings.fuelgauge.batterytip.actions.BatteryDefenderAction; import com.android.settings.fuelgauge.batterytip.actions.BatterySaverAction; import com.android.settings.fuelgauge.batterytip.actions.OpenBatterySaverAction; import com.android.settings.fuelgauge.batterytip.actions.OpenRestrictAppFragmentAction; import com.android.settings.fuelgauge.batterytip.actions.RestrictAppAction; +import com.android.settings.fuelgauge.batterytip.tips.BatteryDefenderTip; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.EarlyWarningTip; import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip; @@ -53,6 +55,7 @@ public class BatteryTipUtilsTest { private RestrictAppTip mRestrictAppTip; private EarlyWarningTip mEarlyWarningTip; private LowBatteryTip mLowBatteryTip; + private BatteryDefenderTip mBatteryDefenderTip; @Before public void setUp() { @@ -67,6 +70,7 @@ public class BatteryTipUtilsTest { mLowBatteryTip = spy( new LowBatteryTip(BatteryTip.StateType.NEW, false /* powerSaveModeOn */, "" /* summary */)); + mBatteryDefenderTip = spy(new BatteryDefenderTip(BatteryTip.StateType.NEW)); } @Test @@ -116,4 +120,13 @@ public class BatteryTipUtilsTest { assertThat(BatteryTipUtils.getActionForBatteryTip(mLowBatteryTip, mSettingsActivity, mFragment)).isInstanceOf(OpenBatterySaverAction.class); } + + @Test + public void + testGetActionForBatteryTip_typeBatteryDefenderStateNew_returnActionBatteryDefender() { + when(mBatteryDefenderTip.getState()).thenReturn(BatteryTip.StateType.NEW); + + assertThat(BatteryTipUtils.getActionForBatteryTip(mBatteryDefenderTip, mSettingsActivity, + mFragment)).isInstanceOf(BatteryDefenderAction.class); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java new file mode 100644 index 00000000000..a1f9d1f21b7 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.fuelgauge.batterytip.detectors; + +import static com.google.common.truth.Truth.assertThat; + +import com.android.settings.fuelgauge.BatteryInfo; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class BatteryDefenderDetectorTest { + + @Mock + private BatteryInfo mBatteryInfo; + private BatteryDefenderDetector mBatteryDefenderDetector; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mBatteryInfo.discharging = false; + + mBatteryDefenderDetector = new BatteryDefenderDetector(mBatteryInfo); + } + + @Test + public void testDetect_notOverheated_tipInvisible() { + mBatteryInfo.isOverheated = false; + + assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse(); + } + + @Test + public void testDetect_isOverheated_tipNew() { + mBatteryInfo.isOverheated = true; + + assertThat(mBatteryDefenderDetector.detect().getState()) + .isEqualTo(BatteryTip.StateType.NEW); + } +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java new file mode 100644 index 00000000000..c6eb15de000 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.settings.fuelgauge.batterytip.tips; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import com.android.settings.R; + +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; + +@RunWith(RobolectricTestRunner.class) +public class BatteryDefenderTipTest { + + private Context mContext; + private BatteryDefenderTip mBatteryDefenderTip; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + mBatteryDefenderTip = new BatteryDefenderTip(BatteryTip.StateType.NEW); + } + + @Test + public void getTitle_showTitle() { + assertThat(mBatteryDefenderTip.getTitle(mContext)) + .isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_title)); + } + + @Test + public void getSummary_showSummary() { + assertThat(mBatteryDefenderTip.getSummary(mContext)) + .isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_summary)); + } + + @Test + public void getIcon_showIcon() { + assertThat(mBatteryDefenderTip.getIconId()) + .isEqualTo(R.drawable.ic_battery_status_good_24dp); + } +}