--- /dev/null
+<!--
+ 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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#0F9D58"
+ android:pathData="M13,7h-2v2h2L13,7zM13,11h-2v6h2v-6zM17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,
+ 1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14z"/>
+</vector>
<string name="battery_tip_smart_battery_title">Turn on smart battery manager</string>
<!-- Summary for the smart battery tip [CHAR LIMIT=NONE] -->
<string name="battery_tip_smart_battery_summary">Turn on to optimize battery usage</string>
+ <!-- Title for the early heads up tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_early_heads_up_title">Turn on Low Battery Mode</string>
+ <!-- Summary for the early hedas up tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_early_heads_up_summary">Extend your battery life</string>
+ <!-- Title when early heads up is solved [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_early_heads_up_done_title">Low Battery Mode is on</string>
+ <!-- Summary when early heads up is solved [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_early_heads_up_done_summary">Some features are limited</string>
<!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
<string name="battery_tip_high_usage_title" product="default">Phone used heavily</string>
<!-- Title for the battery high usage tip [CHAR LIMIT=NONE] -->
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.EarlyWarningDetector;
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
import com.android.settings.fuelgauge.batterytip.detectors.SmartBatteryDetector;
final List<BatteryTip> tips = new ArrayList<>();
final BatteryTipPolicy policy = new BatteryTipPolicy(getContext());
final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG);
+ final Context context = getContext();
mVisibleTips = 0;
addBatteryTipFromDetector(tips, new LowBatteryDetector(policy, batteryInfo));
addBatteryTipFromDetector(tips,
- new HighUsageDetector(getContext(), policy, mBatteryStatsHelper));
+ new HighUsageDetector(context, policy, mBatteryStatsHelper));
addBatteryTipFromDetector(tips,
- new SmartBatteryDetector(policy, getContext().getContentResolver()));
+ new SmartBatteryDetector(policy, context.getContentResolver()));
+ addBatteryTipFromDetector(tips, new EarlyWarningDetector(policy, context));
// Add summary detector at last since it need other detectors to update the mVisibleTips
addBatteryTipFromDetector(tips, new SummaryDetector(policy, mVisibleTips));
import android.app.Fragment;
import com.android.settings.SettingsActivity;
+import com.android.settings.fuelgauge.batterytip.actions.BatterySaverAction;
import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction;
import com.android.settings.fuelgauge.batterytip.actions.SmartBatteryAction;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
switch (batteryTip.getType()) {
case BatteryTip.TipType.SMART_BATTERY_MANAGER:
return new SmartBatteryAction(settingsActivity, fragment);
+ case BatteryTip.TipType.BATTERY_SAVER:
+ return new BatterySaverAction(settingsActivity.getApplicationContext());
default:
return null;
}
--- /dev/null
+/*
+ * 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.actions;
+
+import android.content.Context;
+import android.os.PowerManager;
+
+public class BatterySaverAction extends BatteryTipAction {
+ private PowerManager mPowerManager;
+
+ public BatterySaverAction(Context context) {
+ super(context);
+ mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ }
+
+ /**
+ * Handle the action when user clicks positive button
+ */
+ @Override
+ public void handlePositiveAction() {
+ mPowerManager.setPowerSaveMode(true);
+ }
+}
--- /dev/null
+/*
+ * 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.detectors;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.PowerManager;
+
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
+import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.EarlyWarningTip;
+import com.android.settings.overlay.FeatureFactory;
+
+/**
+ * Detector whether to early warning tip.
+ */
+public class EarlyWarningDetector implements BatteryTipDetector {
+ private BatteryTipPolicy mPolicy;
+ private PowerManager mPowerManager;
+ private Context mContext;
+ private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
+
+ public EarlyWarningDetector(BatteryTipPolicy policy, Context context) {
+ mPolicy = policy;
+ mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ mContext = context;
+ mPowerUsageFeatureProvider = FeatureFactory.getFactory(
+ context).getPowerUsageFeatureProvider(context);
+ }
+
+ @Override
+ public BatteryTip detect() {
+ final Intent batteryBroadcast = mContext.registerReceiver(null,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+ final boolean discharging =
+ batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0;
+ final boolean powerSaveModeOn = mPowerManager.isPowerSaveMode();
+ final boolean earlyWarning = mPowerUsageFeatureProvider.getEarlyWarningSignal(mContext,
+ EarlyWarningDetector.class.getName());
+
+ final int state =
+ mPolicy.batterySaverTipEnabled && !powerSaveModeOn && discharging && earlyWarning
+ ? BatteryTip.StateType.NEW
+ : BatteryTip.StateType.INVISIBLE;
+ return new EarlyWarningTip(state, powerSaveModeOn);
+ }
+}
--- /dev/null
+/*
+ * 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 android.content.Context;
+import android.os.Parcel;
+
+import com.android.settings.R;
+
+/**
+ * Tip to show early warning if battery couldn't make to usual charging time
+ */
+public class EarlyWarningTip extends BatteryTip {
+ private boolean mPowerSaveModeOn;
+
+ public EarlyWarningTip(@StateType int state, boolean powerSaveModeOn) {
+ super(TipType.BATTERY_SAVER, state, false /* showDialog */);
+ mPowerSaveModeOn = powerSaveModeOn;
+ }
+
+ public EarlyWarningTip(Parcel in) {
+ super(in);
+ mPowerSaveModeOn = in.readBoolean();
+ }
+
+ @Override
+ public CharSequence getTitle(Context context) {
+ return context.getString(
+ mState == StateType.HANDLED
+ ? R.string.battery_tip_early_heads_up_done_title
+ : R.string.battery_tip_early_heads_up_title);
+ }
+
+ @Override
+ public CharSequence getSummary(Context context) {
+ return context.getString(
+ mState == StateType.HANDLED
+ ? R.string.battery_tip_early_heads_up_done_summary
+ : R.string.battery_tip_early_heads_up_summary);
+ }
+
+ @Override
+ public int getIconId() {
+ return mState == StateType.HANDLED
+ ? R.drawable.ic_perm_device_information_green_24dp
+ : R.drawable.ic_battery_alert_24dp;
+ }
+
+ @Override
+ public void updateState(BatteryTip tip) {
+ final EarlyWarningTip earlyHeadsUpTip = (EarlyWarningTip) tip;
+ if (mPowerSaveModeOn != earlyHeadsUpTip.mPowerSaveModeOn) {
+ mPowerSaveModeOn = earlyHeadsUpTip.mPowerSaveModeOn;
+ mState = earlyHeadsUpTip.mPowerSaveModeOn ? StateType.HANDLED : StateType.NEW;
+ } else if (mState != StateType.HANDLED) {
+ mState = earlyHeadsUpTip.getState();
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeBoolean(mPowerSaveModeOn);
+ }
+
+ public boolean isPowerSaveModeOn() {
+ return mPowerSaveModeOn;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ public BatteryTip createFromParcel(Parcel in) {
+ return new EarlyWarningTip(in);
+ }
+
+ public BatteryTip[] newArray(int size) {
+ return new EarlyWarningTip[size];
+ }
+ };
+}
--- /dev/null
+/*
+ * 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.detectors;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.BatteryManager;
+import android.os.PowerManager;
+
+import com.android.settings.TestConfig;
+import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
+import com.android.settings.testutils.FakeFeatureFactory;
+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 EarlyWarningDetectorTest {
+ private Context mContext;
+ private BatteryTipPolicy mPolicy;
+ private EarlyWarningDetector mEarlyWarningDetector;
+ @Mock
+ private Intent mIntent;
+ @Mock
+ private PowerManager mPowerManager;
+ private FakeFeatureFactory mFakeFeatureFactory;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+ mPolicy = spy(new BatteryTipPolicy(mContext));
+ doReturn(mPowerManager).when(mContext).getSystemService(Context.POWER_SERVICE);
+ doReturn(mIntent).when(mContext).registerReceiver(any(), any());
+ doReturn(0).when(mIntent).getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ doReturn(true).when(mFakeFeatureFactory.powerUsageFeatureProvider).getEarlyWarningSignal(
+ any(), any());
+
+ mEarlyWarningDetector = new EarlyWarningDetector(mPolicy, mContext);
+ }
+
+ @Test
+ public void testDetect_policyDisabled_tipInvisible() {
+ ReflectionHelpers.setField(mPolicy, "batterySaverTipEnabled", false);
+
+ assertThat(mEarlyWarningDetector.detect().isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDetect_batterySaverOn_tipInvisible() {
+ doReturn(true).when(mPowerManager).isPowerSaveMode();
+
+ assertThat(mEarlyWarningDetector.detect().isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDetect_charging_tipInvisible() {
+ doReturn(1).when(mIntent).getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+
+ assertThat(mEarlyWarningDetector.detect().isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDetect_noEarlyWarning_tipInvisible() {
+ doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).getEarlyWarningSignal(
+ any(), any());
+
+ assertThat(mEarlyWarningDetector.detect().isVisible()).isFalse();
+ }
+
+}
--- /dev/null
+/*
+ * 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 android.content.Context;
+import android.os.Parcel;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class EarlyWarningTipTest {
+ private Context mContext;
+ private EarlyWarningTip mEarlyWarningTip;
+
+ @Before
+ public void setUp() {
+ mContext = RuntimeEnvironment.application;
+ mEarlyWarningTip = new EarlyWarningTip(BatteryTip.StateType.NEW,
+ false /* powerSaveModeOn */);
+ }
+
+ @Test
+ public void testParcelable() {
+ Parcel parcel = Parcel.obtain();
+ mEarlyWarningTip.writeToParcel(parcel, mEarlyWarningTip.describeContents());
+ parcel.setDataPosition(0);
+
+ final EarlyWarningTip parcelTip = new EarlyWarningTip(parcel);
+
+ assertThat(parcelTip.isPowerSaveModeOn()).isFalse();
+ }
+
+ @Test
+ public void testInfo_stateNew_displayPowerModeInfo() {
+ final EarlyWarningTip tip = new EarlyWarningTip(BatteryTip.StateType.NEW,
+ false /* powerModeOn */);
+
+ assertThat(tip.getTitle(mContext)).isEqualTo("Turn on Low Battery Mode");
+ assertThat(tip.getSummary(mContext)).isEqualTo("Extend your battery life");
+ assertThat(tip.getIconId()).isEqualTo(R.drawable.ic_battery_alert_24dp);
+ }
+
+ @Test
+ public void testInfo_stateHandled_displayPowerModeHandledInfo() {
+ final EarlyWarningTip tip = new EarlyWarningTip(BatteryTip.StateType.HANDLED,
+ false /* powerModeOn */);
+
+ assertThat(tip.getTitle(mContext)).isEqualTo("Low Battery Mode is on");
+ assertThat(tip.getSummary(mContext)).isEqualTo("Some features are limited");
+ assertThat(tip.getIconId()).isEqualTo(R.drawable.ic_perm_device_information_green_24dp);
+ }
+
+ @Test
+ public void testUpdate_powerModeTurnedOn_typeBecomeHandled() {
+ final EarlyWarningTip nextTip = new EarlyWarningTip(BatteryTip.StateType.INVISIBLE,
+ true /* powerModeOn */);
+
+ mEarlyWarningTip.updateState(nextTip);
+
+ assertThat(mEarlyWarningTip.getState()).isEqualTo(BatteryTip.StateType.HANDLED);
+ }
+}