diff --git a/res/values/strings.xml b/res/values/strings.xml index e4e311dfac5..978c2947faf 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4892,6 +4892,11 @@ Not now + + Based on your usage, your battery usually lasts about %1$s when fully charged.\n\nIf you need to extend your battery life, turn on Battery Saver. + + If you need to extend your battery life, turn on Battery Saver + Smart battery manager diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java index 9e172de102c..b39e4ef8fbf 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragment.java @@ -32,11 +32,13 @@ import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.fuelgauge.Estimate; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController.BatteryTipListener; import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; +import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip; import com.android.settingslib.utils.StringUtil; @@ -72,9 +74,18 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme switch (mBatteryTip.getType()) { case BatteryTip.TipType.SUMMARY: - case BatteryTip.TipType.LOW_BATTERY: - //TODO(b/70570352): add dialog - return null; + final long averageTimeMs = ((SummaryTip) mBatteryTip).getAverageTimeMs(); + final String message = context.getString( + averageTimeMs == Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN + ? R.string.battery_tip_dialog_summary_message_no_estimation + : R.string.battery_tip_dialog_summary_message, + StringUtil.formatElapsedTime(context, averageTimeMs, + false /* withSeconds */)); + + return new AlertDialog.Builder(context) + .setMessage(message) + .setPositiveButton(android.R.string.ok, null) + .create(); case BatteryTip.TipType.HIGH_DEVICE_USAGE: final HighUsageTip highUsageTip = (HighUsageTip) mBatteryTip; final RecyclerView view = (RecyclerView) LayoutInflater.from(context).inflate( diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java index ebb4790cd96..5efc04adbe4 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java @@ -22,6 +22,7 @@ import android.support.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.Estimate; import com.android.settings.fuelgauge.batterytip.detectors.EarlyWarningDetector; import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector; import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector; @@ -70,7 +71,7 @@ public class BatteryTipLoader extends AsyncLoader> { tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper).detect()); tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect()); tips.add(new EarlyWarningDetector(policy, context).detect()); - tips.add(new SummaryDetector(policy).detect()); + tips.add(new SummaryDetector(policy, batteryInfo.averageTimeToDischarge).detect()); tips.add(new RestrictAppDetector(context, policy).detect()); Collections.sort(tips); @@ -83,7 +84,8 @@ public class BatteryTipLoader extends AsyncLoader> { private List getFakeData() { final List tips = new ArrayList<>(); - tips.add(new SummaryTip(BatteryTip.StateType.NEW)); + tips.add(new SummaryTip(BatteryTip.StateType.NEW, + Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN)); tips.add(new LowBatteryTip(BatteryTip.StateType.NEW)); return tips; diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java index d2af58973d7..9e4778222b6 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceController.java @@ -27,6 +27,7 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.settings.SettingsActivity; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.InstrumentedPreferenceFragment; +import com.android.settings.fuelgauge.Estimate; import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; @@ -82,7 +83,8 @@ public class BatteryTipPreferenceController extends BasePreferenceController { mPreferenceGroup = (PreferenceGroup) screen.findPreference(getPreferenceKey()); // Add summary tip in advance to avoid UI flakiness - final SummaryTip summaryTip = new SummaryTip(BatteryTip.StateType.NEW); + final SummaryTip summaryTip = new SummaryTip(BatteryTip.StateType.NEW, + Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN); mPreferenceGroup.addPreference(summaryTip.buildPreference(mPrefContext)); } diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetector.java index a45dc0955fe..0a20aac83cd 100644 --- a/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetector.java +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetector.java @@ -26,9 +26,11 @@ import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; */ public class SummaryDetector implements BatteryTipDetector { private BatteryTipPolicy mPolicy; + private long mAverageTimeMs; - public SummaryDetector(BatteryTipPolicy policy) { + public SummaryDetector(BatteryTipPolicy policy, long averageTimeMs) { mPolicy = policy; + mAverageTimeMs = averageTimeMs; } @Override @@ -37,6 +39,6 @@ public class SummaryDetector implements BatteryTipDetector { final int state = mPolicy.summaryEnabled ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE; - return new SummaryTip(state); + return new SummaryTip(state, mAverageTimeMs); } } diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java index 899375436a1..8ed86920057 100644 --- a/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java +++ b/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java @@ -19,6 +19,7 @@ package com.android.settings.fuelgauge.batterytip.tips; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; @@ -28,13 +29,17 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; * Tip to show general summary about battery life */ public class SummaryTip extends BatteryTip { + private long mAverageTimeMs; - public SummaryTip(@StateType int state) { - super(TipType.SUMMARY, state, false /* showDialog */); + public SummaryTip(@StateType int state, long averageTimeMs) { + super(TipType.SUMMARY, state, true /* showDialog */); + mAverageTimeMs = averageTimeMs; } - private SummaryTip(Parcel in) { + @VisibleForTesting + SummaryTip(Parcel in) { super(in); + mAverageTimeMs = in.readLong(); } @Override @@ -57,12 +62,22 @@ public class SummaryTip extends BatteryTip { mState = tip.mState; } + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeLong(mAverageTimeMs); + } + @Override public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) { metricsFeatureProvider.action(context, MetricsProto.MetricsEvent.ACTION_SUMMARY_TIP, mState); } + public long getAverageTimeMs() { + return mAverageTimeMs; + } + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public BatteryTip createFromParcel(Parcel in) { return new SummaryTip(in); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java index 9f1bb319a82..6f8bb26e504 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipDialogFragmentTest.java @@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batterytip; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.robolectric.Shadows.shadowOf; @@ -26,9 +27,11 @@ import android.content.Context; import android.text.format.DateUtils; import com.android.settings.R; +import com.android.settings.fuelgauge.Estimate; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; +import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowUtils; @@ -54,6 +57,7 @@ public class BatteryTipDialogFragmentTest { private static final String PACKAGE_NAME = "com.android.app"; private static final String DISPLAY_NAME = "app"; private static final long SCREEN_TIME_MS = DateUtils.HOUR_IN_MILLIS; + private static final long AVERAGE_TIME_MS = DateUtils.HOUR_IN_MILLIS; private BatteryTipDialogFragment mDialogFragment; private Context mContext; @@ -61,6 +65,7 @@ public class BatteryTipDialogFragmentTest { private RestrictAppTip mRestrictedOneAppTip; private RestrictAppTip mRestrictAppsTip; private UnrestrictAppTip mUnrestrictAppTip; + private SummaryTip mSummaryTip; @Before public void setUp() { @@ -85,6 +90,8 @@ public class BatteryTipDialogFragmentTest { new ArrayList<>(restrictApps)); mUnrestrictAppTip = new UnrestrictAppTip(BatteryTip.StateType.NEW, appInfo); + mSummaryTip = spy(new SummaryTip(BatteryTip.StateType.NEW, + Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN)); } @Test @@ -151,4 +158,32 @@ public class BatteryTipDialogFragmentTest { assertThat(shadowDialog.getMessage()) .isEqualTo(mContext.getString(R.string.battery_tip_unrestrict_app_dialog_message)); } + + @Test + public void testOnCreateDialog_summaryTipWithEstimation_fireDialogWithEstimation() { + doReturn(AVERAGE_TIME_MS).when(mSummaryTip).getAverageTimeMs(); + mDialogFragment = BatteryTipDialogFragment.newInstance(mSummaryTip); + + FragmentTestUtil.startFragment(mDialogFragment); + + final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog(); + ShadowAlertDialog shadowDialog = shadowOf(dialog); + + assertThat(shadowDialog.getMessage()).isEqualTo( + "Based on your usage, your battery usually lasts about 1h when fully charged" + + ".\n\nIf you need to extend your battery life, turn on Battery Saver."); + } + + @Test + public void testOnCreateDialog_summaryTipWithoutEstimation_fireDialogWithoutEstimation() { + mDialogFragment = BatteryTipDialogFragment.newInstance(mSummaryTip); + + FragmentTestUtil.startFragment(mDialogFragment); + + final AlertDialog dialog = (AlertDialog) ShadowDialog.getLatestDialog(); + ShadowAlertDialog shadowDialog = shadowOf(dialog); + + assertThat(shadowDialog.getMessage()).isEqualTo( + "If you need to extend your battery life, turn on Battery Saver"); + } } 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 6f898b249bb..0ac94c01082 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java @@ -15,8 +15,11 @@ */ package com.android.settings.fuelgauge.batterytip; -import static com.android.settings.fuelgauge.batterytip.tips.BatteryTip.TipType.SMART_BATTERY_MANAGER; +import static com.android.settings.fuelgauge.batterytip.tips.BatteryTip.TipType + .SMART_BATTERY_MANAGER; + import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; @@ -30,6 +33,7 @@ import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceManager; import android.support.v7.preference.PreferenceScreen; +import android.text.format.DateUtils; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.SettingsActivity; @@ -54,6 +58,8 @@ public class BatteryTipPreferenceControllerTest { private static final String KEY_PREF = "battery_tip"; private static final String KEY_TIP = "key_battery_tip"; + private static final long AVERAGE_TIME_MS = DateUtils.HOUR_IN_MILLIS; + @Mock private BatteryTipPreferenceController.BatteryTipListener mBatteryTipListener; @Mock @@ -87,9 +93,9 @@ public class BatteryTipPreferenceControllerTest { mFeatureFactory = FakeFeatureFactory.setupForTest(); mOldBatteryTips = new ArrayList<>(); - mOldBatteryTips.add(new SummaryTip(BatteryTip.StateType.NEW)); + mOldBatteryTips.add(new SummaryTip(BatteryTip.StateType.NEW, AVERAGE_TIME_MS)); mNewBatteryTips = new ArrayList<>(); - mNewBatteryTips.add(new SummaryTip(BatteryTip.StateType.INVISIBLE)); + mNewBatteryTips.add(new SummaryTip(BatteryTip.StateType.INVISIBLE, AVERAGE_TIME_MS)); mBatteryTipPreferenceController = new BatteryTipPreferenceController(mContext, KEY_PREF, mSettingsActivity, null, mBatteryTipListener); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetectorTest.java index 5ca1ad24260..df38d34d48b 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetectorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetectorTest.java @@ -19,6 +19,8 @@ package com.android.settings.fuelgauge.batterytip.detectors; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; +import android.text.format.DateUtils; + import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -33,6 +35,7 @@ import org.robolectric.util.ReflectionHelpers; public class SummaryDetectorTest { private BatteryTipPolicy mPolicy; + private static final long AVERAGE_TIME_MS = DateUtils.HOUR_IN_MILLIS; @Before public void setUp() { @@ -44,14 +47,14 @@ public class SummaryDetectorTest { @Test public void testDetect_disabledByPolicy_tipInvisible() { ReflectionHelpers.setField(mPolicy, "summaryEnabled", false); - SummaryDetector detector = new SummaryDetector(mPolicy); + SummaryDetector detector = new SummaryDetector(mPolicy, AVERAGE_TIME_MS); assertThat(detector.detect().isVisible()).isFalse(); } @Test public void testDetect_notDisabled_tipVisible() { - SummaryDetector detector = new SummaryDetector(mPolicy); + SummaryDetector detector = new SummaryDetector(mPolicy, AVERAGE_TIME_MS); assertThat(detector.detect().isVisible()).isTrue(); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTipTest.java new file mode 100644 index 00000000000..221c37fcbc7 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTipTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 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 static org.mockito.Mockito.verify; + +import android.content.Context; +import android.os.Parcel; +import android.text.format.DateUtils; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class SummaryTipTest { + + private static final long AVERAGE_TIME_MS = DateUtils.HOUR_IN_MILLIS; + + @Mock + private MetricsFeatureProvider mMetricsFeatureProvider; + private Context mContext; + private SummaryTip mSummaryTip; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + mSummaryTip = + new SummaryTip(BatteryTip.StateType.NEW, AVERAGE_TIME_MS); + } + + @Test + public void testParcelable() { + Parcel parcel = Parcel.obtain(); + mSummaryTip.writeToParcel(parcel, mSummaryTip.describeContents()); + parcel.setDataPosition(0); + + final SummaryTip parcelTip = new SummaryTip(parcel); + + assertThat(parcelTip.getAverageTimeMs()).isEqualTo(AVERAGE_TIME_MS); + } + + @Test + public void testLog() { + mSummaryTip.log(mContext, mMetricsFeatureProvider); + + verify(mMetricsFeatureProvider).action(mContext, + MetricsProto.MetricsEvent.ACTION_SUMMARY_TIP, BatteryTip.StateType.NEW); + } +}