From ede87ce19f297467217870027f970ad5fefdd9e3 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Wed, 28 Feb 2018 11:21:39 -0800 Subject: [PATCH] Add dialog for summary tip Also change SummaryTip to store the time data, which is used in the dialog. If "Full last charge" time is available, show normal message otherwise show message without it. Bug: 72997971 Test: RunSettingsRoboTests Change-Id: I4ce94f0935465a18275edb13e3be343313427c3b --- res/values/strings.xml | 5 ++ .../batterytip/BatteryTipDialogFragment.java | 17 ++++- .../batterytip/BatteryTipLoader.java | 6 +- .../BatteryTipPreferenceController.java | 4 +- .../batterytip/detectors/SummaryDetector.java | 6 +- .../fuelgauge/batterytip/tips/SummaryTip.java | 21 +++++- .../BatteryTipDialogFragmentTest.java | 35 +++++++++ .../BatteryTipPreferenceControllerTest.java | 12 ++- .../detectors/SummaryDetectorTest.java | 7 +- .../batterytip/tips/SummaryTipTest.java | 74 +++++++++++++++++++ 10 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTipTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 185732d7b70..504bcd3e5f7 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); + } +}