From: jackqdyulei Date: Thu, 14 Dec 2017 19:15:04 +0000 (-0800) Subject: Add BatteryTipDetector and LowBatteryTip stuffs. X-Git-Tag: android-x86-9.0-r1~130^2~3^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=5f0b09648b6f43fc5ca01473266cf85b28de832b;p=android-x86%2Fpackages-apps-Settings.git Add BatteryTipDetector and LowBatteryTip stuffs. This cl adds the infra of BatteryTipDetector and use LowBatteryTip as an example(tip model + detector). Also add SummaryTipDetector and related tests Bug: 70570352 Test: RunSettingsRoboTests Change-Id: Icf1349b6ede9eb7ee5ed69b39ee3a2661ac660fa --- diff --git a/res/drawable/ic_perm_device_information_red_24dp.xml b/res/drawable/ic_perm_device_information_red_24dp.xml new file mode 100644 index 0000000000..135e212411 --- /dev/null +++ b/res/drawable/ic_perm_device_information_red_24dp.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 65f73c81bf..c94eb1ba3b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4742,6 +4742,10 @@ Battery is in good shape Apps are behaving normally + + Low battery capacity + + Battery can\'t provide good battery life Stop app? diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java index b8cb6c48b1..9c3f48c0a6 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java @@ -17,13 +17,21 @@ package com.android.settings.fuelgauge.batterytip; import android.content.Context; +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.batterytip.detectors.BatteryTipDetector; +import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector; +import com.android.settings.fuelgauge.batterytip.detectors.SummaryDetector; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip; import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; import com.android.settingslib.utils.AsyncLoader; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -36,18 +44,31 @@ public class BatteryTipLoader extends AsyncLoader> { private static final boolean USE_FAKE_DATA = false; private BatteryStatsHelper mBatteryStatsHelper; + private BatteryUtils mBatteryUtils; + @VisibleForTesting + int mVisibleTips; public BatteryTipLoader(Context context, BatteryStatsHelper batteryStatsHelper) { super(context); mBatteryStatsHelper = batteryStatsHelper; + mBatteryUtils = BatteryUtils.getInstance(context); } @Override public List loadInBackground() { - List tips = new ArrayList<>(); + if (USE_FAKE_DATA) { + return getFakeData(); + } + final List tips = new ArrayList<>(); + final BatteryTipPolicy policy = new BatteryTipPolicy(getContext()); + final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG); + mVisibleTips = 0; - //TODO(b/70570352): add battery tip detectors - tips.add(new SummaryTip(BatteryTip.StateType.NEW)); + addBatteryTipFromDetector(tips, new LowBatteryDetector(policy, batteryInfo)); + // Add summary detector at last since it need other detectors to update the mVisibleTips + addBatteryTipFromDetector(tips, new SummaryDetector(policy, mVisibleTips)); + + Collections.sort(tips); return tips; } @@ -55,4 +76,20 @@ public class BatteryTipLoader extends AsyncLoader> { protected void onDiscardResult(List result) { } + private List getFakeData() { + final List tips = new ArrayList<>(); + tips.add(new SummaryTip(BatteryTip.StateType.NEW)); + tips.add(new LowBatteryTip(BatteryTip.StateType.NEW)); + + return tips; + } + + @VisibleForTesting + void addBatteryTipFromDetector(final List tips, + final BatteryTipDetector detector) { + final BatteryTip batteryTip = detector.detect(); + mVisibleTips += batteryTip.isVisible() ? 1 : 0; + tips.add(batteryTip); + } + } diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryTipDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryTipDetector.java new file mode 100644 index 0000000000..cb38e40faf --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryTipDetector.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2017 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.batterytip.tips.BatteryTip; + +public interface BatteryTipDetector { + /** + * Detect and update the status of {@link BatteryTip} + * + * @return a not null {@link BatteryTip} + */ + BatteryTip detect(); +} diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java new file mode 100644 index 0000000000..2a6302efbc --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2017 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 android.text.format.DateUtils; + +import com.android.settings.fuelgauge.BatteryInfo; +import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip; + +/** + * Detect whether the battery is too low + */ +public class LowBatteryDetector implements BatteryTipDetector { + private BatteryInfo mBatteryInfo; + private BatteryTipPolicy mPolicy; + + public LowBatteryDetector(BatteryTipPolicy policy, BatteryInfo batteryInfo) { + mPolicy = policy; + mBatteryInfo = batteryInfo; + } + + @Override + public BatteryTip detect() { + // Show it if battery life is less than mPolicy.lowBatteryHour + final boolean isShown = mPolicy.lowBatteryEnabled && mBatteryInfo.discharging + && mBatteryInfo.remainingTimeUs < mPolicy.lowBatteryHour * DateUtils.HOUR_IN_MILLIS; + return new LowBatteryTip( + isShown ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE); + } +} diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetector.java new file mode 100644 index 0000000000..8c1783bd66 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetector.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 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.batterytip.BatteryTipPolicy; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.fuelgauge.batterytip.tips.SummaryTip; + +/** + * Detector whether to show summary tip. This detector should be executed as the last + * {@link BatteryTipDetector} since it need the most up-to-date {@code visibleTips} + */ +public class SummaryDetector implements BatteryTipDetector { + private BatteryTipPolicy mPolicy; + private int mVisibleTips; + + public SummaryDetector(BatteryTipPolicy policy, int visibleTips) { + mPolicy = policy; + mVisibleTips = visibleTips; + } + + @Override + public BatteryTip detect() { + // Show it if there is no other tips shown + final int state = mPolicy.summaryEnabled && mVisibleTips == 0 + ? BatteryTip.StateType.NEW + : BatteryTip.StateType.INVISIBLE; + return new SummaryTip(state); + } +} diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java index e633272487..17e395ef18 100644 --- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java +++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java @@ -31,7 +31,7 @@ import java.lang.annotation.RetentionPolicy; * Each {@link BatteryTip} contains basic data(e.g. title, summary, icon) as well as the * pre-defined action(e.g. turn on battery saver) */ -public abstract class BatteryTip { +public abstract class BatteryTip implements Comparable { @Retention(RetentionPolicy.SOURCE) @IntDef({StateType.NEW, StateType.HANDLED, @@ -114,4 +114,13 @@ public abstract class BatteryTip { public int getState() { return mState; } + + public boolean isVisible() { + return mState != StateType.INVISIBLE; + } + + @Override + public int compareTo(BatteryTip o) { + return mType - o.mType; + } } diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/LowBatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/LowBatteryTip.java new file mode 100644 index 0000000000..8605fbb631 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/tips/LowBatteryTip.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017 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.app.Dialog; +import android.content.Context; + +import com.android.settings.R; + +/** + * Tip to show current battery life is short + */ +public class LowBatteryTip extends BatteryTip { + + public LowBatteryTip(@StateType int state) { + mShowDialog = false; + mState = state; + mType = TipType.LOW_BATTERY; + } + + @Override + public CharSequence getTitle(Context context) { + return context.getString(R.string.battery_tip_low_battery_title); + } + + @Override + public CharSequence getSummary(Context context) { + return context.getString(R.string.battery_tip_low_battery_summary); + } + + @Override + public int getIconId() { + return R.drawable.ic_perm_device_information_red_24dp; + } + + @Override + public void updateState(BatteryTip tip) { + mState = tip.mState; + } + + @Override + public void action() { + // do nothing + } + + @Override + public Dialog buildDialog() { + //TODO(b/70570352): create the dialog for low battery tip and add test + return null; + } +} diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java index ab2a6c3f19..2a2deabfa8 100644 --- a/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java +++ b/src/com/android/settings/fuelgauge/batterytip/tips/SummaryTip.java @@ -29,6 +29,7 @@ public class SummaryTip extends BatteryTip { public SummaryTip(@StateType int state) { mShowDialog = false; mState = state; + mType = TipType.SUMMARY; } @Override diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java new file mode 100644 index 0000000000..e4e8eef572 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2017 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; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; + +import android.content.Context; + +import com.android.internal.os.BatteryStatsHelper; +import com.android.settings.TestConfig; +import com.android.settings.fuelgauge.batterytip.detectors.BatteryTipDetector; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class BatteryTipLoaderTest { + @Mock + private BatteryStatsHelper mBatteryStatsHelper; + @Mock + private BatteryTipDetector mBatteryTipDetector; + @Mock + private BatteryTip mBatteryTip; + private Context mContext; + private BatteryTipLoader mBatteryTipLoader; + private List mBatteryTips; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + doReturn(mBatteryTip).when(mBatteryTipDetector).detect(); + mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryStatsHelper); + mBatteryTips = new ArrayList<>(); + } + + @Test + public void testAddBatteryTipFromDetector_tipVisible_addAndUpdateCount() { + doReturn(true).when(mBatteryTip).isVisible(); + mBatteryTipLoader.mVisibleTips = 0; + + mBatteryTipLoader.addBatteryTipFromDetector(mBatteryTips, mBatteryTipDetector); + + assertThat(mBatteryTips.contains(mBatteryTip)).isTrue(); + assertThat(mBatteryTipLoader.mVisibleTips).isEqualTo(1); + } + + @Test + public void testAddBatteryTipFromDetector_tipInvisible_doNotAddCount() { + doReturn(false).when(mBatteryTip).isVisible(); + mBatteryTipLoader.mVisibleTips = 0; + + mBatteryTipLoader.addBatteryTipFromDetector(mBatteryTips, mBatteryTipDetector); + + assertThat(mBatteryTips.contains(mBatteryTip)).isTrue(); + assertThat(mBatteryTipLoader.mVisibleTips).isEqualTo(0); + } + +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java new file mode 100644 index 0000000000..4866a6a734 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2017 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 static org.mockito.Mockito.spy; + +import android.content.Context; +import android.text.format.DateUtils; + +import com.android.settings.TestConfig; +import com.android.settings.fuelgauge.BatteryInfo; +import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class LowBatteryDetectorTest { + private Context mContext; + @Mock + private BatteryInfo mBatteryInfo; + private BatteryTipPolicy mPolicy; + private LowBatteryDetector mLowBatteryDetector; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + mPolicy = spy(new BatteryTipPolicy(mContext)); + mLowBatteryDetector = new LowBatteryDetector(mPolicy, mBatteryInfo); + } + + @Test + public void testDetect_disabledByPolicy_tipInvisible() { + ReflectionHelpers.setField(mPolicy, "lowBatteryEnabled", false); + + assertThat(mLowBatteryDetector.detect().isVisible()).isFalse(); + } + + @Test + public void testDetect_shortBatteryLife_tipVisible() { + mBatteryInfo.discharging = true; + mBatteryInfo.remainingTimeUs = 1 * DateUtils.MINUTE_IN_MILLIS; + + assertThat(mLowBatteryDetector.detect().isVisible()).isTrue(); + } + + @Test + public void testDetect_longBatteryLife_tipInvisible() { + mBatteryInfo.discharging = true; + mBatteryInfo.remainingTimeUs = 1 * DateUtils.DAY_IN_MILLIS; + + assertThat(mLowBatteryDetector.detect().isVisible()).isFalse(); + } +} 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 new file mode 100644 index 0000000000..389a6c3fc2 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/SummaryDetectorTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 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 static org.mockito.Mockito.spy; + +import android.content.Context; + +import com.android.settings.TestConfig; +import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SummaryDetectorTest { + private Context mContext; + private BatteryTipPolicy mPolicy; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + mPolicy = spy(new BatteryTipPolicy(mContext)); + } + + @Test + public void testDetect_disabledByPolicy_tipInvisible() { + ReflectionHelpers.setField(mPolicy, "summaryEnabled", false); + SummaryDetector detector = new SummaryDetector(mPolicy, 0 /* visibleTips */); + + assertThat(detector.detect().isVisible()).isFalse(); + } + + @Test + public void testDetect_noOtherTips_tipVisible() { + SummaryDetector detector = new SummaryDetector(mPolicy, 0 /* visibleTips */); + + assertThat(detector.detect().isVisible()).isTrue(); + } + + @Test + public void testDetect_hasOtherTips_tipInVisible() { + SummaryDetector detector = new SummaryDetector(mPolicy, 1 /* visibleTips */); + + assertThat(detector.detect().isVisible()).isFalse(); + } +}