diff --git a/res/drawable-night/ic_battery_status_protected_24dp.xml b/res/drawable-night/ic_battery_status_protected_24dp.xml
new file mode 100644
index 00000000000..23386cb8048
--- /dev/null
+++ b/res/drawable-night/ic_battery_status_protected_24dp.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/drawable/ic_battery_status_protected_24dp.xml b/res/drawable/ic_battery_status_protected_24dp.xml
new file mode 100644
index 00000000000..8841710e43d
--- /dev/null
+++ b/res/drawable/ic_battery_status_protected_24dp.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4a2c38a3fb8..28378c48969 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4682,8 +4682,18 @@
Charging is paused
Protecting battery to extend battery lifespan
-
- %1$s
+
+ Charging to %1$s to protect the battery
+
+ When your tablet is docked, charging will be paused at %1$s to extend battery lifespan
+
+ Charging paused to protect battery
+
+ When your tablet is docked, charging is paused at %1$s to extend battery lifespan
+
+ Charging to full
+
+ To protect your battery, charging will be paused at %1$s the next time your tablet is docked
Learn more about charging is paused
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 558e0bfb391..665be1f0f2c 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -98,6 +98,7 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ intentFilter.addAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
final Intent intent = mContext.registerReceiver(this, intentFilter);
updateBatteryStatus(intent, true /* forceUpdate */);
@@ -132,6 +133,8 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
mBatteryHealth = batteryHealth;
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
+ } else if (BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION.equals(intent.getAction())) {
+ mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
}
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index ab89b94c956..cfa537b31f5 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -42,6 +42,8 @@ import com.android.settingslib.fuelgauge.EstimateKt;
import com.android.settingslib.utils.PowerUtil;
import com.android.settingslib.utils.StringUtil;
+import java.text.NumberFormat;
+
public class BatteryInfo {
private static final String TAG = "BatteryInfo";
@@ -49,6 +51,7 @@ public class BatteryInfo {
public CharSequence remainingLabel;
public int batteryLevel;
public int batteryStatus;
+ public int pluggedStatus;
public boolean discharging = true;
public boolean isOverheated;
public long remainingTimeUs = 0;
@@ -253,7 +256,8 @@ public class BatteryInfo {
info.mBatteryUsageStats = batteryUsageStats;
info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
- info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
+ info.pluggedStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+ info.mCharging = info.pluggedStatus != 0;
info.averageTimeToDischarge = estimate.getAverageDischargeTime();
info.isOverheated = batteryBroadcast.getIntExtra(
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
@@ -280,25 +284,37 @@ public class BatteryInfo {
BatteryManager.BATTERY_STATUS_UNKNOWN);
info.discharging = false;
info.suggestionLabel = null;
- if (info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL) {
+ int dockDefenderMode = BatteryUtils.getCurrentDockDefenderMode(context, info);
+ if ((info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL
+ && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
+ || dockDefenderMode == BatteryUtils.DockDefenderMode.ACTIVE) {
+ // Battery defender active, battery charging paused
info.remainingLabel = null;
int chargingLimitedResId = R.string.power_charging_limited;
- info.chargeLabel =
- context.getString(chargingLimitedResId, info.batteryPercentString);
- } else if (chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
+ info.chargeLabel = context.getString(chargingLimitedResId, info.batteryPercentString);
+ } else if ((chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL
+ && dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
+ || dockDefenderMode == BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED) {
+ // Battery is charging to full
info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
- final CharSequence timeString = StringUtil.formatElapsedTime(
- context,
- PowerUtil.convertUsToMs(info.remainingTimeUs),
- false /* withSeconds */,
+ final CharSequence timeString = StringUtil.formatElapsedTime(context,
+ (double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */,
true /* collapseTimeUnit */);
int resId = R.string.power_charging_duration;
- info.remainingLabel = context.getString(
- R.string.power_remaining_charging_duration_only, timeString);
+ info.remainingLabel = context.getString(R.string.power_remaining_charging_duration_only,
+ timeString);
info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);
+ } else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
+ // Dock defender will be triggered in the future, charging will be paused at 90%.
+ final int extraValue = context.getResources().getInteger(
+ R.integer.config_battery_extra_tip_value);
+ final String extraPercentage = NumberFormat.getPercentInstance().format(
+ extraValue * 0.01f);
+ info.chargeLabel = context.getString(R.string.power_charging_future_paused,
+ info.batteryPercentString, extraPercentage);
} else {
- final String chargeStatusLabel =
- Utils.getBatteryStatus(context, batteryBroadcast, compactStatus);
+ final String chargeStatusLabel = Utils.getBatteryStatus(context, batteryBroadcast,
+ compactStatus);
info.remainingLabel = null;
info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
resources.getString(R.string.power_charging, info.batteryPercentString,
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index c5a8b0002a7..19d0727c19f 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -33,6 +33,7 @@ import android.os.Process;
import android.os.SystemClock;
import android.os.UidBatteryConsumer;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.Base64;
import android.util.Log;
@@ -76,6 +77,11 @@ public class BatteryUtils {
/** Special UID for aggregated other users. */
public static final long UID_OTHER_USERS = Long.MIN_VALUE;
+ /** Flag to check if the dock defender mode has been temporarily bypassed */
+ public static final String SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS = "dock_defender_bypass";
+
+ public static final String BYPASS_DOCK_DEFENDER_ACTION = "battery.dock.defender.bypass";
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({StatusType.SCREEN_USAGE,
StatusType.FOREGROUND,
@@ -89,6 +95,18 @@ public class BatteryUtils {
int ALL = 3;
}
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DockDefenderMode.FUTURE_BYPASS,
+ DockDefenderMode.ACTIVE,
+ DockDefenderMode.TEMPORARILY_BYPASSED,
+ DockDefenderMode.DISABLED})
+ public @interface DockDefenderMode {
+ int FUTURE_BYPASS = 0;
+ int ACTIVE = 1;
+ int TEMPORARILY_BYPASSED = 2;
+ int DISABLED = 3;
+ }
+
private static final String TAG = "BatteryUtils";
private static BatteryUtils sInstance;
@@ -592,4 +610,21 @@ public class BatteryUtils {
? -1 /*invalid battery level*/
: Math.round((level / (float) scale) * 100f);
}
+
+ /** Gets the current dock defender mode */
+ public static int getCurrentDockDefenderMode(Context context, BatteryInfo batteryInfo) {
+ if (batteryInfo.pluggedStatus == BatteryManager.BATTERY_PLUGGED_DOCK) {
+ if (Settings.Global.getInt(context.getContentResolver(),
+ SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0) == 1) {
+ return DockDefenderMode.TEMPORARILY_BYPASSED;
+ } else if (batteryInfo.isOverheated && FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .isExtraDefend()) {
+ return DockDefenderMode.ACTIVE;
+ } else if (!batteryInfo.isOverheated) {
+ return DockDefenderMode.FUTURE_BYPASS;
+ }
+ }
+ return DockDefenderMode.DISABLED;
+ }
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 2faacb749f8..b17afa563fd 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -133,7 +133,7 @@ public interface PowerUsageFeatureProvider {
/**
* Gets a intent for one time bypass charge limited to resume charging.
*/
- Intent getResumeChargeIntent();
+ Intent getResumeChargeIntent(boolean isDockDefender);
/**
* Returns {@link Set} for hidding applications background usage time.
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index ff1edecac8c..856f86a0952 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -142,7 +142,7 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
}
@Override
- public Intent getResumeChargeIntent() {
+ public Intent getResumeChargeIntent(boolean isDockDefender) {
return null;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 95145ba8216..7bdc5d5686a 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -24,6 +24,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
+import com.android.settings.fuelgauge.batterytip.detectors.DockDefenderDetector;
import com.android.settings.fuelgauge.batterytip.detectors.EarlyWarningDetector;
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
@@ -74,6 +75,7 @@ public class BatteryTipLoader extends AsyncLoaderCompat> {
tips.add(new EarlyWarningDetector(policy, context).detect());
tips.add(new BatteryDefenderDetector(
batteryInfo, context.getApplicationContext()).detect());
+ tips.add(new DockDefenderDetector(batteryInfo, context.getApplicationContext()).detect());
Collections.sort(tips);
return tips;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
index 87d4a0b44a5..08df2e494f6 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -37,11 +37,10 @@ public class BatteryDefenderDetector implements BatteryTipDetector {
@Override
public BatteryTip detect() {
- if (mBatteryInfo.isOverheated) {
- final boolean extraDefend = FeatureFactory.getFactory(mContext)
- .getPowerUsageFeatureProvider(mContext)
- .isExtraDefend();
- return new BatteryDefenderTip(BatteryTip.StateType.NEW, extraDefend);
+ if (mBatteryInfo.isOverheated && !FeatureFactory.getFactory(mContext)
+ .getPowerUsageFeatureProvider(mContext)
+ .isExtraDefend()) {
+ return new BatteryDefenderTip(BatteryTip.StateType.NEW);
}
return new BatteryDefenderTip(BatteryTip.StateType.INVISIBLE);
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java
new file mode 100644
index 00000000000..8a839d392d8
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetector.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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 com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
+
+/**
+ * Detect whether the dock defender mode is enabled.
+ */
+public class DockDefenderDetector implements BatteryTipDetector {
+ private final BatteryInfo mBatteryInfo;
+ private final Context mContext;
+
+ public DockDefenderDetector(BatteryInfo batteryInfo, Context context) {
+ mBatteryInfo = batteryInfo;
+ mContext = context;
+ }
+
+ @Override
+ public BatteryTip detect() {
+ int mode = BatteryUtils.getCurrentDockDefenderMode(mContext, mBatteryInfo);
+ return new DockDefenderTip(
+ mode != BatteryUtils.DockDefenderMode.DISABLED
+ ? BatteryTip.StateType.NEW
+ : BatteryTip.StateType.INVISIBLE,
+ mode);
+ }
+
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
index 2fb56500834..1ccc29c18e3 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -32,24 +32,15 @@ import com.android.settings.widget.CardPreference;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import java.text.NumberFormat;
-
/**
* Tip to show current battery is overheated
*/
public class BatteryDefenderTip extends BatteryTip {
private static final String TAG = "BatteryDefenderTip";
- private boolean mExtraDefend = false;
public BatteryDefenderTip(@StateType int state) {
- this(state, false);
- }
-
- public BatteryDefenderTip(@StateType int state, boolean extraDefend) {
- super(TipType.BATTERY_DEFENDER, state, true /* showDialog */);
- mExtraDefend = extraDefend;
- mShowDialog = false;
+ super(TipType.BATTERY_DEFENDER, state, false /* showDialog */);
}
private BatteryDefenderTip(Parcel in) {
@@ -63,14 +54,6 @@ public class BatteryDefenderTip extends BatteryTip {
@Override
public CharSequence getSummary(Context context) {
- if (mExtraDefend) {
- final int extraValue = context.getResources()
- .getInteger(R.integer.config_battery_extra_tip_value);
- final String extraPercentage = NumberFormat.getPercentInstance()
- .format(extraValue * 0.01f);
- return context.getString(
- R.string.battery_tip_limited_temporarily_extra_summary, extraPercentage);
- }
return context.getString(R.string.battery_tip_limited_temporarily_summary);
}
@@ -131,7 +114,7 @@ public class BatteryDefenderTip extends BatteryTip {
final Intent intent =
FeatureFactory.getFactory(context)
.getPowerUsageFeatureProvider(context)
- .getResumeChargeIntent();
+ .getResumeChargeIntent(false);
if (intent != null) {
context.sendBroadcast(intent);
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
index 5aee0291e4d..fcf5e09ba1b 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
@@ -58,7 +58,8 @@ public abstract class BatteryTip implements Comparable, Parcelable {
TipType.REDUCED_BATTERY,
TipType.LOW_BATTERY,
TipType.REMOVE_APP_RESTRICTION,
- TipType.BATTERY_DEFENDER})
+ TipType.BATTERY_DEFENDER,
+ TipType.DOCK_DEFENDER})
public @interface TipType {
int SMART_BATTERY_MANAGER = 0;
int APP_RESTRICTION = 1;
@@ -69,6 +70,7 @@ public abstract class BatteryTip implements Comparable, Parcelable {
int SUMMARY = 6;
int REMOVE_APP_RESTRICTION = 7;
int BATTERY_DEFENDER = 8;
+ int DOCK_DEFENDER = 9;
}
@VisibleForTesting
@@ -78,12 +80,13 @@ public abstract class BatteryTip implements Comparable, Parcelable {
TIP_ORDER.append(TipType.BATTERY_SAVER, 0);
TIP_ORDER.append(TipType.LOW_BATTERY, 1);
TIP_ORDER.append(TipType.BATTERY_DEFENDER, 2);
- TIP_ORDER.append(TipType.APP_RESTRICTION, 3);
- TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 4);
- TIP_ORDER.append(TipType.SUMMARY, 5);
- TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 6);
- TIP_ORDER.append(TipType.REDUCED_BATTERY, 7);
- TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 8);
+ TIP_ORDER.append(TipType.DOCK_DEFENDER, 3);
+ TIP_ORDER.append(TipType.APP_RESTRICTION, 4);
+ TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 5);
+ TIP_ORDER.append(TipType.SUMMARY, 6);
+ TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 7);
+ TIP_ORDER.append(TipType.REDUCED_BATTERY, 8);
+ TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 9);
}
private static final String KEY_PREFIX = "key_battery_tip";
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
new file mode 100644
index 00000000000..2ba3dcd12e2
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTip.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 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.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Parcel;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.BatteryUtils.DockDefenderMode;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.CardPreference;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import java.text.NumberFormat;
+
+/**
+ * Tip to show dock defender status
+ */
+public class DockDefenderTip extends BatteryTip {
+ private static final String TAG = "DockDefenderTip";
+ private int mMode;
+
+ public DockDefenderTip(@StateType int state, @DockDefenderMode int mode) {
+ super(TipType.DOCK_DEFENDER, state, false);
+ mMode = mode;
+ }
+
+ private DockDefenderTip(Parcel in) {
+ super(in);
+ }
+
+ public int getMode() {
+ return mMode;
+ }
+
+ @Override
+ public CharSequence getTitle(Context context) {
+ switch (mMode) {
+ case DockDefenderMode.FUTURE_BYPASS:
+ return context.getString(R.string.battery_tip_dock_defender_future_bypass_title,
+ getExtraPercentage(context));
+ case DockDefenderMode.ACTIVE:
+ return context.getString(R.string.battery_tip_dock_defender_active_title);
+ case DockDefenderMode.TEMPORARILY_BYPASSED:
+ return context.getString(
+ R.string.battery_tip_dock_defender_temporarily_bypassed_title);
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public CharSequence getSummary(Context context) {
+ switch (mMode) {
+ case DockDefenderMode.FUTURE_BYPASS:
+ return context.getString(R.string.battery_tip_dock_defender_future_bypass_summary,
+ getExtraPercentage(context));
+ case DockDefenderMode.ACTIVE:
+ return context.getString(R.string.battery_tip_dock_defender_active_summary,
+ getExtraPercentage(context));
+ case DockDefenderMode.TEMPORARILY_BYPASSED:
+ return context.getString(
+ R.string.battery_tip_dock_defender_temporarily_bypassed_summary,
+ getExtraPercentage(context));
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public int getIconId() {
+ return R.drawable.ic_battery_status_protected_24dp;
+ }
+
+ @Override
+ public void updateState(BatteryTip tip) {
+ mState = tip.mState;
+ if (tip instanceof DockDefenderTip) {
+ mMode = ((DockDefenderTip) tip).mMode;
+ }
+ }
+
+ @Override
+ public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
+ metricsFeatureProvider.action(context, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
+ mState);
+ }
+
+ @Override
+ public void updatePreference(Preference preference) {
+ super.updatePreference(preference);
+ final Context context = preference.getContext();
+
+ CardPreference cardPreference = castToCardPreferenceSafely(preference);
+ if (cardPreference == null) {
+ Log.e(TAG, "cast Preference to CardPreference failed");
+ return;
+ }
+
+ cardPreference.setSelectable(false);
+ switch (mMode) {
+ case DockDefenderMode.FUTURE_BYPASS:
+ case DockDefenderMode.ACTIVE:
+ cardPreference.setPrimaryButtonText(
+ context.getString(R.string.battery_tip_charge_to_full_button));
+ cardPreference.setPrimaryButtonClickListener(unused -> {
+ resumeCharging(context);
+ mMode = DockDefenderMode.TEMPORARILY_BYPASSED;
+ context.sendBroadcast(new Intent().setAction(
+ BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION).setPackage(
+ context.getPackageName()).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+ | Intent.FLAG_RECEIVER_FOREGROUND));
+ updatePreference(preference);
+ });
+ cardPreference.setPrimaryButtonVisible(true);
+ break;
+ case DockDefenderMode.TEMPORARILY_BYPASSED:
+ cardPreference.setPrimaryButtonVisible(false);
+ break;
+ default:
+ cardPreference.setVisible(false);
+ return;
+ }
+
+ cardPreference.setSecondaryButtonText(context.getString(R.string.learn_more));
+ //TODO: update helper string
+ cardPreference.setSecondaryButtonClickListener(
+ button -> button.startActivityForResult(
+ HelpUtils.getHelpIntent(
+ context,
+ context.getString(R.string.help_url_battery_defender),
+ /* backupContext */ ""), /* requestCode */ 0));
+ cardPreference.setSecondaryButtonVisible(true);
+ cardPreference.setSecondaryButtonContentDescription(context.getString(
+ R.string.battery_tip_limited_temporarily_sec_button_content_description));
+
+ }
+
+ private CardPreference castToCardPreferenceSafely(Preference preference) {
+ return preference instanceof CardPreference ? (CardPreference) preference : null;
+ }
+
+ private void resumeCharging(Context context) {
+ final Intent intent =
+ FeatureFactory.getFactory(context)
+ .getPowerUsageFeatureProvider(context)
+ .getResumeChargeIntent(true);
+ if (intent != null) {
+ context.sendBroadcast(intent);
+ }
+
+ Log.i(TAG, "send resume charging broadcast intent=" + intent);
+ }
+
+ private String getExtraPercentage(Context context) {
+ final int extraValue = context.getResources()
+ .getInteger(R.integer.config_battery_extra_tip_value);
+ return NumberFormat.getPercentInstance()
+ .format(extraValue * 0.01f);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ public BatteryTip createFromParcel(Parcel in) {
+ return new DockDefenderTip(in);
+ }
+
+ public BatteryTip[] newArray(int size) {
+ return new DockDefenderTip[size];
+ }
+ };
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index 867d8f44b7e..79bd84bd1ec 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -55,6 +55,7 @@ public class BatteryBroadcastReceiverTest {
private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
private Context mContext;
private Intent mChargingIntent;
+ private Intent mDockDefenderBypassIntent;
@Before
public void setUp() {
@@ -72,6 +73,8 @@ public class BatteryBroadcastReceiverTest {
mChargingIntent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_INTENT_SCALE);
mChargingIntent
.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
+ mDockDefenderBypassIntent = new Intent(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
+
}
@Test
@@ -130,6 +133,13 @@ public class BatteryBroadcastReceiverTest {
verify(mBatteryListener, never()).onBatteryChanged(anyInt());
}
+ @Test
+ public void testOnReceive_dockDefenderBypassed_listenerInvoked() {
+ mBatteryBroadcastReceiver.onReceive(mContext, mDockDefenderBypassIntent);
+
+ verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
+ }
+
@Test
public void testRegister_updateBatteryStatus() {
doReturn(mChargingIntent).when(mContext).registerReceiver(any(), any());
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index 6bf61356452..284dbe3dbb9 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -36,6 +36,7 @@ import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.BatteryUsageStats;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.SparseIntArray;
import com.android.internal.os.BatteryStatsHistoryIterator;
@@ -66,6 +67,7 @@ public class BatteryInfoTest {
private static final String STATUS_CHARGING_NO_TIME = "50% - charging";
private static final String STATUS_CHARGING_TIME = "50% - 0 min left until full";
private static final String STATUS_NOT_CHARGING = "Not charging";
+ private static final String STATUS_CHARGING_FUTURE_BYPASS = "50% - Charging to 12%";
private static final long REMAINING_TIME_NULL = -1;
private static final long REMAINING_TIME = 2;
// Strings are defined in frameworks/base/packages/SettingsLib/res/values/strings.xml
@@ -97,6 +99,10 @@ public class BatteryInfoTest {
mDisChargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent();
mChargingBatteryBroadcast = BatteryTestUtils.getChargingIntent();
+
+ doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+ Settings.Global.putInt(mContext.getContentResolver(),
+ BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
}
@Test
@@ -231,6 +237,7 @@ public class BatteryInfoTest {
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
false /* shortString */);
+
assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING);
assertThat(info.remainingLabel.toString())
.isEqualTo(TEST_CHARGE_TIME_REMAINING_STRINGIFIED);
@@ -265,6 +272,62 @@ public class BatteryInfoTest {
assertThat(info.chargeLabel.toString()).contains(expectedString);
}
+ @Test
+ public void testGetBatteryInfo_dockDefenderActive_updateChargeString() {
+ final String expectedString =
+ mContext.getString(R.string.battery_tip_limited_temporarily_title);
+ doReturn(TEST_CHARGE_TIME_REMAINING / 1000)
+ .when(mBatteryUsageStats).getChargeTimeRemainingMs();
+ doReturn(true).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+ Intent intent = BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+ 50 /* level */,
+ 100 /* scale */,
+ BatteryManager.BATTERY_STATUS_CHARGING)
+ .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+
+ BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, intent,
+ mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+ false /* shortString */);
+
+ assertThat(info.chargeLabel.toString()).contains(expectedString);
+ }
+
+ @Test
+ public void testGetBatteryInfo_dockDefenderTemporarilyBypassed_updateChargeLabel() {
+ doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs();
+ mChargingBatteryBroadcast
+ .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+ Settings.Global.putInt(mContext.getContentResolver(),
+ BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
+
+ BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
+ BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+ 50 /* level */,
+ 100 /* scale */,
+ BatteryManager.BATTERY_STATUS_CHARGING),
+ mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+ false /* shortString */);
+
+ assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_TIME);
+ }
+
+ @Test
+ public void testGetBatteryInfo_dockDefenderFutureBypass_updateChargeLabel() {
+ doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+ mChargingBatteryBroadcast
+ .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+
+ BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
+ BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+ 50 /* level */,
+ 100 /* scale */,
+ BatteryManager.BATTERY_STATUS_CHARGING),
+ mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+ false /* shortString */);
+
+ assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_FUTURE_BYPASS);
+ }
+
// Make our battery stats return a sequence of battery events.
private void mockBatteryStatsHistory() {
// Mock out new data every time iterateBatteryStatsHistory is called.
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index 66a5e7f8bd0..648685a8d8f 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -132,7 +132,12 @@ public class PowerUsageFeatureProviderImplTest {
}
@Test
- public void testGetResumeChargeIntent_returnNull() {
- assertThat(mPowerFeatureProvider.getResumeChargeIntent()).isNull();
+ public void testGetResumeChargeIntentWithoutDockDefender_returnNull() {
+ assertThat(mPowerFeatureProvider.getResumeChargeIntent(false)).isNull();
+ }
+
+ @Test
+ public void testGetResumeChargeIntentWithDockDefender_returnNull() {
+ assertThat(mPowerFeatureProvider.getResumeChargeIntent(true)).isNull();
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
index 95280b669bc..6d3965e2266 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
@@ -53,6 +53,7 @@ public class BatteryTipLoaderTest {
BatteryTip.TipType.BATTERY_SAVER,
BatteryTip.TipType.LOW_BATTERY,
BatteryTip.TipType.BATTERY_DEFENDER,
+ BatteryTip.TipType.DOCK_DEFENDER,
BatteryTip.TipType.HIGH_DEVICE_USAGE,
BatteryTip.TipType.SMART_BATTERY_MANAGER};
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
index 90e7ad762a8..f81a4be8d63 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -18,10 +18,15 @@ package com.android.settings.fuelgauge.batterytip.detectors;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.junit.Test;
@@ -36,6 +41,9 @@ public class BatteryDefenderDetectorTest {
@Mock
private BatteryInfo mBatteryInfo;
private BatteryDefenderDetector mBatteryDefenderDetector;
+ private Context mContext;
+
+ private FakeFeatureFactory mFakeFeatureFactory;
@Before
public void setUp() {
@@ -43,20 +51,42 @@ public class BatteryDefenderDetectorTest {
mBatteryInfo.discharging = false;
+ mContext = ApplicationProvider.getApplicationContext();
+
mBatteryDefenderDetector = new BatteryDefenderDetector(
- mBatteryInfo, ApplicationProvider.getApplicationContext());
+ mBatteryInfo, mContext);
+
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
}
@Test
- public void testDetect_notOverheated_tipInvisible() {
+ public void testDetect_notOverheatedNotExtraDefend_tipInvisible() {
mBatteryInfo.isOverheated = false;
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
}
@Test
- public void testDetect_isOverheated_tipNew() {
+ public void testDetect_notOverheatedIsExtraDefend_tipInvisible() {
+ mBatteryInfo.isOverheated = false;
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+ assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDetect_isOverheatedIsExtraDefend_tipInvisible() {
+ mBatteryInfo.isOverheated = false;
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+ assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDetect_isOverheatedNotExtraDefend_tipNew() {
mBatteryInfo.isOverheated = true;
+ when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
assertThat(mBatteryDefenderDetector.detect().getState())
.isEqualTo(BatteryTip.StateType.NEW);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
new file mode 100644
index 00000000000..9652a00ca18
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
+import com.android.settings.testutils.BatteryTestUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class DockDefenderDetectorTest {
+
+ private BatteryInfo mBatteryInfo;
+ private DockDefenderDetector mDockDefenderDetector;
+ private Context mContext;
+ private FakeFeatureFactory mFakeFeatureFactory;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mBatteryInfo = new BatteryInfo();
+ mBatteryInfo.pluggedStatus = BatteryManager.BATTERY_PLUGGED_DOCK;
+ mDockDefenderDetector = new DockDefenderDetector(mBatteryInfo, mContext);
+ Intent intent = BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
+ 50 /* level */, 100 /* scale */, BatteryManager.BATTERY_STATUS_CHARGING);
+ doReturn(intent).when(mContext).registerReceiver(eq(null),
+ refEq(new IntentFilter(Intent.ACTION_BATTERY_CHANGED)));
+
+ Settings.Global.putInt(mContext.getContentResolver(),
+ BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
+ mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
+ }
+
+ @Test
+ public void testDetect_dockDefenderTemporarilyBypassed() {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED);
+ }
+
+ @Test
+ public void testDetect_dockDefenderActive() {
+ mBatteryInfo.isOverheated = true;
+ doReturn(true).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.ACTIVE);
+ }
+
+ @Test
+ public void testDetect_dockDefenderFutureBypass() {
+ mBatteryInfo.isOverheated = false;
+ doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.FUTURE_BYPASS);
+ }
+
+ @Test
+ public void testDetect_overheatedTrue_dockDefenderDisabled() {
+ mBatteryInfo.isOverheated = true;
+ doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.DISABLED);
+ }
+
+ @Test
+ public void testDetect_pluggedInAC_dockDefenderDisabled() {
+ mBatteryInfo.pluggedStatus = BatteryManager.BATTERY_PLUGGED_AC;
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.DISABLED);
+ }
+
+ @Test
+ public void testDetect_overheatedTrueAndDockDefenderNotTriggered_dockDefenderDisabled() {
+ doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
+ mBatteryInfo.isOverheated = true;
+
+ BatteryTip batteryTip = mDockDefenderDetector.detect();
+
+ assertTrue(batteryTip instanceof DockDefenderTip);
+ assertEquals(((DockDefenderTip) batteryTip).getMode(),
+ BatteryUtils.DockDefenderMode.DISABLED);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
index 6bd6b26b78c..8b6033a8811 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -79,19 +79,11 @@ public class BatteryDefenderTipTest {
}
@Test
- public void getSummary_notExtraDefended_showNonExtraDefendedSummary() {
+ public void getSummary_showSummary() {
assertThat(mBatteryDefenderTip.getSummary(mContext))
.isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_summary));
}
- @Test
- public void getSummary_extraDefended_showExtraDefendedSummary() {
- BatteryDefenderTip defenderTip = new BatteryDefenderTip(
- BatteryTip.StateType.NEW, /* extraDefended= */ true);
-
- assertThat(defenderTip.getSummary(mContext).toString()).isEqualTo("12%");
- }
-
@Test
public void getIcon_showIcon() {
assertThat(mBatteryDefenderTip.getIconId())
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
new file mode 100644
index 00000000000..d917d8921a7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/DockDefenderTipTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2022 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.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.widget.CardPreference;
+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.shadows.ShadowLog;
+
+import java.text.NumberFormat;
+
+@RunWith(RobolectricTestRunner.class)
+public class DockDefenderTipTest {
+ private Context mContext;
+ private DockDefenderTip mDockDefenderTipFutureBypass;
+ private DockDefenderTip mDockDefenderTipActive;
+ private DockDefenderTip mDockDefenderTipTemporarilyBypassed;
+ private DockDefenderTip mDockDefenderTipDisabled;
+ private FakeFeatureFactory mFeatureFactory;
+ private MetricsFeatureProvider mMetricsFeatureProvider;
+
+ @Mock
+ private Preference mPreference;
+ @Mock
+ private CardPreference mCardPreference;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = ApplicationProvider.getApplicationContext();
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
+
+ mDockDefenderTipFutureBypass = new DockDefenderTip(BatteryTip.StateType.NEW,
+ BatteryUtils.DockDefenderMode.FUTURE_BYPASS);
+ mDockDefenderTipActive = new DockDefenderTip(BatteryTip.StateType.NEW,
+ BatteryUtils.DockDefenderMode.ACTIVE);
+ mDockDefenderTipTemporarilyBypassed = new DockDefenderTip(BatteryTip.StateType.NEW,
+ BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED);
+ mDockDefenderTipDisabled = new DockDefenderTip(BatteryTip.StateType.INVISIBLE,
+ BatteryUtils.DockDefenderMode.DISABLED);
+
+ doReturn(mContext).when(mPreference).getContext();
+ doReturn(mContext).when(mCardPreference).getContext();
+ }
+
+ @Test
+ public void testGetTitle() {
+ assertThat(mDockDefenderTipFutureBypass.getTitle(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_future_bypass_title,
+ getExtraPercentage(mContext)));
+ assertThat(mDockDefenderTipActive.getTitle(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_active_title));
+ assertThat(mDockDefenderTipTemporarilyBypassed.getTitle(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_temporarily_bypassed_title));
+ assertThat(mDockDefenderTipDisabled.getTitle(mContext)).isNull();
+ }
+
+ @Test
+ public void testGetSummary() {
+ assertThat(mDockDefenderTipFutureBypass.getSummary(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_future_bypass_summary,
+ getExtraPercentage(mContext)));
+ assertThat(mDockDefenderTipActive.getSummary(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_active_summary,
+ getExtraPercentage(mContext)));
+ assertThat(mDockDefenderTipTemporarilyBypassed.getSummary(mContext).toString()).isEqualTo(
+ mContext.getString(R.string.battery_tip_dock_defender_temporarily_bypassed_summary,
+ getExtraPercentage(mContext)));
+ assertThat(mDockDefenderTipDisabled.getSummary(mContext)).isNull();
+ }
+
+ @Test
+ public void testGetIconId() {
+ assertThat(mDockDefenderTipFutureBypass.getIconId()).isEqualTo(
+ R.drawable.ic_battery_status_protected_24dp);
+ }
+
+ @Test
+ public void testUpdateState() {
+ mDockDefenderTipTemporarilyBypassed.updateState(mDockDefenderTipDisabled);
+
+ assertThat(mDockDefenderTipTemporarilyBypassed.getState()).isEqualTo(
+ BatteryTip.StateType.INVISIBLE);
+ assertThat(mDockDefenderTipTemporarilyBypassed.getMode()).isEqualTo(
+ BatteryUtils.DockDefenderMode.DISABLED);
+ }
+
+ @Test
+ public void testLog() {
+ mDockDefenderTipActive.log(mContext, mMetricsFeatureProvider);
+
+ verify(mMetricsFeatureProvider).action(mContext, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
+ mDockDefenderTipActive.getState());
+ }
+
+
+ @Test
+ public void testUpdatePreference_dockDefenderTipFutureBypass() {
+ mDockDefenderTipFutureBypass.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(true);
+ verify(mCardPreference).setPrimaryButtonText(
+ mContext.getString(R.string.battery_tip_charge_to_full_button));
+ verifySecondaryButton();
+ }
+
+ @Test
+ public void testUpdatePreference_dockDefenderTipActive() {
+ mDockDefenderTipActive.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(true);
+ verify(mCardPreference).setPrimaryButtonText(
+ mContext.getString(R.string.battery_tip_charge_to_full_button));
+ verifySecondaryButton();
+ }
+
+ @Test
+ public void testUpdatePreference_dockDefenderTipTemporarilyBypassed() {
+ mDockDefenderTipTemporarilyBypassed.updatePreference(mCardPreference);
+
+ verify(mCardPreference).setPrimaryButtonVisible(false);
+ verify(mCardPreference, never()).setPrimaryButtonText(any());
+ verifySecondaryButton();
+ }
+
+ private void verifySecondaryButton() {
+ verify(mCardPreference).setSecondaryButtonText(mContext.getString(R.string.learn_more));
+ verify(mCardPreference).setSecondaryButtonVisible(true);
+ verify(mCardPreference).setSecondaryButtonContentDescription(mContext.getString(
+ R.string.battery_tip_limited_temporarily_sec_button_content_description));
+ }
+
+ @Test
+ public void updatePreference_castFail_logErrorMessage() {
+ mDockDefenderTipActive.updatePreference(mPreference);
+
+ assertThat(getLastErrorLog()).isEqualTo("cast Preference to CardPreference failed");
+ }
+
+ private String getLastErrorLog() {
+ return ShadowLog.getLogsForTag(DockDefenderTip.class.getSimpleName()).stream().filter(
+ log -> log.type == Log.ERROR).reduce((first, second) -> second).orElse(
+ createErrorLog("No Error Log")).msg;
+ }
+
+ private ShadowLog.LogItem createErrorLog(String msg) {
+ return new ShadowLog.LogItem(Log.ERROR, "tag", msg, null);
+ }
+
+ private String getExtraPercentage(Context context) {
+ final int extraValue = context.getResources().getInteger(
+ R.integer.config_battery_extra_tip_value);
+ return NumberFormat.getPercentInstance().format(extraValue * 0.01f);
+ }
+
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
index ffb3197ed4c..485caef1c9e 100644
--- a/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/BatteryTestUtils.java
@@ -134,7 +134,7 @@ public class BatteryTestUtils {
}
}
- private static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
+ public static Intent getCustomBatteryIntent(int plugged, int level, int scale, int status) {
Intent intent = new Intent();
intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged);
intent.putExtra(BatteryManager.EXTRA_LEVEL, level);