Enhance battery settings limit charge tip
- Add dialog for limit charge tips - Add action button to make limit charge tips can bypass charge limited - Fix layout typo Screenshot: https://screenshot.googleplex.com/5ngtD2sJAKSQZD3.png Bug: 196315151 Bug: 197769934 Test: make SettingsRoboTests Change-Id: I0901c56ae93691c984376852da78cde9078caaf0 Merged-In: I0901c56ae93691c984376852da78cde9078caaf0
This commit is contained in:
@@ -6158,6 +6158,12 @@
|
|||||||
<string name="battery_tip_limited_temporarily_title">Charging temporarily limited</string>
|
<string name="battery_tip_limited_temporarily_title">Charging temporarily limited</string>
|
||||||
<!-- Summary for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
|
<!-- Summary for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
|
||||||
<string name="battery_tip_limited_temporarily_summary">To preserve your battery. Learn more.</string>
|
<string name="battery_tip_limited_temporarily_summary">To preserve your battery. Learn more.</string>
|
||||||
|
<!-- Text of battery limited temporarily tip resume charge button. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_limited_temporarily_dialog_resume_charge">Resume charging</string>
|
||||||
|
<!-- Message of battery limited temporarily tip. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_limited_temporarily_dialog_msg" product="default">In certain conditions, like high temperatures and long charging periods, charging may be limited to <xliff:g id="percent" example="50%">%1$s</xliff:g> to help preserve battery health.\n\nWhen those conditions end, your phone will automatically charge normally.</string>
|
||||||
|
<!-- Message of battery limited temporarily tip. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_limited_temporarily_dialog_msg" product="tablet">In certain conditions, like high temperatures and long charging periods, charging may be limited to <xliff:g id="percent" example="50%">%1$s</xliff:g> to help preserve battery health.\n\nWhen those conditions end, your tablet will automatically charge normally.</string>
|
||||||
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
||||||
<string name="battery_tip_dialog_message" product="default">Because you’ve used your phone more than usual, your battery may run out sooner than it normally would.\n\nApps using most battery:</string>
|
<string name="battery_tip_dialog_message" product="default">Because you’ve used your phone more than usual, your battery may run out sooner than it normally would.\n\nApps using most battery:</string>
|
||||||
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
android:title="@string/smart_battery_manager_title"
|
android:title="@string/smart_battery_manager_title"
|
||||||
settings:keywords="@string/keywords_battery_adaptive_preferences">
|
settings:keywords="@string/keywords_battery_adaptive_preferences">
|
||||||
|
|
||||||
<com.android.settingslib.widget.IllustrationPreferencee
|
<com.android.settingslib.widget.IllustrationPreference
|
||||||
android:key="auto_awesome_battery"
|
android:key="auto_awesome_battery"
|
||||||
settings:lottie_rawRes="@raw/auto_awesome_battery_lottie" />
|
settings:lottie_rawRes="@raw/auto_awesome_battery_lottie" />
|
||||||
|
|
||||||
|
@@ -138,6 +138,11 @@ public interface PowerUsageFeatureProvider {
|
|||||||
*/
|
*/
|
||||||
boolean isChartGraphSlotsEnabled(Context context);
|
boolean isChartGraphSlotsEnabled(Context context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a intent for one time bypass charge limited to resume charging.
|
||||||
|
*/
|
||||||
|
Intent getResumeChargeIntent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns battery history data with corresponding timestamp key.
|
* Returns battery history data with corresponding timestamp key.
|
||||||
*/
|
*/
|
||||||
|
@@ -165,6 +165,11 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Intent getResumeChargeIntent() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Long, Map<String, BatteryHistEntry>> getBatteryHistory(Context context) {
|
public Map<Long, Map<String, BatteryHistEntry>> getBatteryHistory(Context context) {
|
||||||
return null;
|
return null;
|
||||||
|
@@ -20,6 +20,9 @@ import android.app.Dialog;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.os.BatteryManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
|
||||||
@@ -40,6 +43,7 @@ import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
|
|||||||
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
|
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
|
||||||
import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
|
import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,6 +54,7 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
|
|||||||
|
|
||||||
private static final String ARG_BATTERY_TIP = "battery_tip";
|
private static final String ARG_BATTERY_TIP = "battery_tip";
|
||||||
private static final String ARG_METRICS_KEY = "metrics_key";
|
private static final String ARG_METRICS_KEY = "metrics_key";
|
||||||
|
private static final double CHARGE_LIMIT_LEVEL = 0.8f;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BatteryTip mBatteryTip;
|
BatteryTip mBatteryTip;
|
||||||
@@ -138,6 +143,28 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
|
|||||||
.setPositiveButton(R.string.battery_tip_unrestrict_app_dialog_ok, this)
|
.setPositiveButton(R.string.battery_tip_unrestrict_app_dialog_ok, this)
|
||||||
.setNegativeButton(R.string.battery_tip_unrestrict_app_dialog_cancel, null)
|
.setNegativeButton(R.string.battery_tip_unrestrict_app_dialog_cancel, null)
|
||||||
.create();
|
.create();
|
||||||
|
case BatteryTip.TipType.BATTERY_DEFENDER:
|
||||||
|
mMetricsFeatureProvider.action(context,
|
||||||
|
SettingsEnums.ACTION_TIP_BATTERY_DEFENDER, mMetricsKey);
|
||||||
|
final String percentage =
|
||||||
|
NumberFormat.getPercentInstance().format(CHARGE_LIMIT_LEVEL);
|
||||||
|
final String message = context.getString(
|
||||||
|
R.string.battery_tip_limited_temporarily_dialog_msg, percentage);
|
||||||
|
final boolean isPluggedIn = isPluggedIn();
|
||||||
|
final AlertDialog.Builder dialogBuilder =
|
||||||
|
new AlertDialog.Builder(context)
|
||||||
|
.setTitle(R.string.battery_tip_limited_temporarily_title)
|
||||||
|
.setMessage(message);
|
||||||
|
if (isPluggedIn) {
|
||||||
|
dialogBuilder
|
||||||
|
.setPositiveButton(
|
||||||
|
R.string.battery_tip_limited_temporarily_dialog_resume_charge,
|
||||||
|
this)
|
||||||
|
.setNegativeButton(R.string.okay, null);
|
||||||
|
} else {
|
||||||
|
dialogBuilder.setPositiveButton(R.string.okay, null);
|
||||||
|
}
|
||||||
|
return dialogBuilder.create();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("unknown type " + mBatteryTip.getType());
|
throw new IllegalArgumentException("unknown type " + mBatteryTip.getType());
|
||||||
}
|
}
|
||||||
@@ -163,4 +190,11 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
|
|||||||
lsn.onBatteryTipHandled(mBatteryTip);
|
lsn.onBatteryTipHandled(mBatteryTip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isPluggedIn() {
|
||||||
|
final Intent batteryIntent = getContext().registerReceiver(null /* receiver */,
|
||||||
|
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||||
|
return batteryIntent != null && batteryIntent.getIntExtra(
|
||||||
|
BatteryManager.EXTRA_PLUGGED, 0) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -16,12 +16,11 @@
|
|||||||
|
|
||||||
package com.android.settings.fuelgauge.batterytip.actions;
|
package com.android.settings.fuelgauge.batterytip.actions;
|
||||||
|
|
||||||
import android.app.settings.SettingsEnums;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settingslib.HelpUtils;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action to open the Support Center article
|
* Action to open the Support Center article
|
||||||
@@ -34,19 +33,13 @@ public class BatteryDefenderAction extends BatteryTipAction {
|
|||||||
mSettingsActivity = settingsActivity;
|
mSettingsActivity = settingsActivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the action when user clicks positive button
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePositiveAction(int metricsKey) {
|
public void handlePositiveAction(int metricsKey) {
|
||||||
mMetricsFeatureProvider.action(mContext,
|
final Intent intent = FeatureFactory.getFactory(mContext)
|
||||||
SettingsEnums.ACTION_TIP_BATTERY_DEFENDER, metricsKey);
|
.getPowerUsageFeatureProvider(mContext).getResumeChargeIntent();
|
||||||
final Intent intent = HelpUtils.getHelpIntent(
|
|
||||||
mContext,
|
|
||||||
mContext.getString(R.string.help_url_battery_defender),
|
|
||||||
getClass().getName());
|
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
mSettingsActivity.startActivityForResult(intent, 0);
|
// Post intent to background thread to avoid UI flaky
|
||||||
|
AsyncTask.execute(() -> mContext.sendBroadcast(intent));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
package com.android.settings.fuelgauge.batterytip.detectors;
|
package com.android.settings.fuelgauge.batterytip.detectors;
|
||||||
|
|
||||||
import com.android.settings.fuelgauge.BatteryInfo;
|
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.BatteryDefenderTip;
|
||||||
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||||
|
|
||||||
@@ -34,7 +33,7 @@ public class BatteryDefenderDetector implements BatteryTipDetector {
|
|||||||
@Override
|
@Override
|
||||||
public BatteryTip detect() {
|
public BatteryTip detect() {
|
||||||
final int state =
|
final int state =
|
||||||
BatteryUtils.isBatteryDefenderOn(mBatteryInfo)
|
mBatteryInfo.isOverheated
|
||||||
? BatteryTip.StateType.NEW
|
? BatteryTip.StateType.NEW
|
||||||
: BatteryTip.StateType.INVISIBLE;
|
: BatteryTip.StateType.INVISIBLE;
|
||||||
return new BatteryDefenderTip(state);
|
return new BatteryDefenderTip(state);
|
||||||
|
@@ -29,7 +29,7 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
|||||||
public class BatteryDefenderTip extends BatteryTip {
|
public class BatteryDefenderTip extends BatteryTip {
|
||||||
|
|
||||||
public BatteryDefenderTip(@StateType int state) {
|
public BatteryDefenderTip(@StateType int state) {
|
||||||
super(TipType.BATTERY_DEFENDER, state, false /* showDialog */);
|
super(TipType.BATTERY_DEFENDER, state, true /* showDialog */);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BatteryDefenderTip(Parcel in) {
|
private BatteryDefenderTip(Parcel in) {
|
||||||
|
@@ -155,4 +155,9 @@ public class PowerUsageFeatureProviderImplTest {
|
|||||||
|
|
||||||
assertThat(mPowerFeatureProvider.isSmartBatterySupported()).isFalse();
|
assertThat(mPowerFeatureProvider.isSmartBatterySupported()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResumeChargeIntent_returnNull() {
|
||||||
|
assertThat(mPowerFeatureProvider.getResumeChargeIntent()).isNull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ import androidx.appcompat.app.AlertDialog;
|
|||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.fuelgauge.batterytip.tips.BatteryDefenderTip;
|
||||||
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||||
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
|
import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip;
|
||||||
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
|
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
|
||||||
@@ -74,6 +75,7 @@ public class BatteryTipDialogFragmentTest {
|
|||||||
private RestrictAppTip mRestrictTwoAppsTip;
|
private RestrictAppTip mRestrictTwoAppsTip;
|
||||||
private UnrestrictAppTip mUnrestrictAppTip;
|
private UnrestrictAppTip mUnrestrictAppTip;
|
||||||
private SummaryTip mSummaryTip;
|
private SummaryTip mSummaryTip;
|
||||||
|
private BatteryDefenderTip mDefenderTip;
|
||||||
private AppInfo mAppInfo;
|
private AppInfo mAppInfo;
|
||||||
private ShadowPackageManager mPackageManager;
|
private ShadowPackageManager mPackageManager;
|
||||||
|
|
||||||
@@ -116,6 +118,7 @@ public class BatteryTipDialogFragmentTest {
|
|||||||
mUnrestrictAppTip = new UnrestrictAppTip(BatteryTip.StateType.NEW, mAppInfo);
|
mUnrestrictAppTip = new UnrestrictAppTip(BatteryTip.StateType.NEW, mAppInfo);
|
||||||
mSummaryTip = spy(new SummaryTip(BatteryTip.StateType.NEW,
|
mSummaryTip = spy(new SummaryTip(BatteryTip.StateType.NEW,
|
||||||
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN));
|
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN));
|
||||||
|
mDefenderTip = new BatteryDefenderTip(BatteryTip.StateType.NEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -243,4 +246,20 @@ public class BatteryTipDialogFragmentTest {
|
|||||||
+ "your phone will suggest actions you can take.\n\nYou can always turn"
|
+ "your phone will suggest actions you can take.\n\nYou can always turn"
|
||||||
+ " on Battery Saver if you’re running low on battery.");
|
+ " on Battery Saver if you’re running low on battery.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnCreateDialog_defenderTip_fireDialog() {
|
||||||
|
mDialogFragment = BatteryTipDialogFragment.newInstance(mDefenderTip, METRICS_KEY);
|
||||||
|
|
||||||
|
FragmentController.setupFragment(mDialogFragment, FragmentActivity.class,
|
||||||
|
0 /* containerViewId */, null /* bundle */);
|
||||||
|
|
||||||
|
final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
|
||||||
|
ShadowAlertDialogCompat shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog);
|
||||||
|
|
||||||
|
assertThat(shadowDialog.getTitle()).isEqualTo(
|
||||||
|
mContext.getString(R.string.battery_tip_limited_temporarily_title));
|
||||||
|
assertThat(shadowDialog.getMessage()).isEqualTo(
|
||||||
|
mContext.getString(R.string.battery_tip_limited_temporarily_dialog_msg, "80%"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2021 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 static com.google.common.truth.Truth.assertThat;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
import android.app.settings.SettingsEnums;
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settings.SettingsActivity;
|
|
||||||
import com.android.settings.testutils.FakeFeatureFactory;
|
|
||||||
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.RobolectricTestRunner;
|
|
||||||
import org.robolectric.RuntimeEnvironment;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
public final class BatteryDefenderActionTest {
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
private FakeFeatureFactory mFeatureFactory;
|
|
||||||
private BatteryDefenderAction mBatteryDefenderAction;
|
|
||||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
|
||||||
|
|
||||||
@Mock private SettingsActivity mSettingsActivity;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
|
|
||||||
mFeatureFactory = FakeFeatureFactory.setupForTest();
|
|
||||||
mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
|
|
||||||
mContext = spy(RuntimeEnvironment.application);
|
|
||||||
doReturn(mContext).when(mSettingsActivity).getApplicationContext();
|
|
||||||
mBatteryDefenderAction = new BatteryDefenderAction(mSettingsActivity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHandlePositiveAction_logMetric() {
|
|
||||||
final int metricKey = 10;
|
|
||||||
mBatteryDefenderAction.handlePositiveAction(metricKey);
|
|
||||||
|
|
||||||
verify(mMetricsFeatureProvider).action(mContext,
|
|
||||||
SettingsEnums.ACTION_TIP_BATTERY_DEFENDER, metricKey);
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user