Add dock defender battery tips
1. Remove the dock defender v1 code
2. Add dock defender battery tips and update
corresponding list item string
Bug: 260687359
Test: Unit test passed and manual test on device
Merged-In: Ib6c09df056744142f42f5e2a13252b58e54c7534
Change-Id: Ib6c09df056744142f42f5e2a13252b58e54c7534
Signed-off-by: Zhenwei Chen <zhenwec@google.com>
(cherry picked from commit 8d11d9ceea
)
This commit is contained in:
committed by
Wesley Wang
parent
80095fa001
commit
1d72ff642c
30
res/drawable-night/ic_battery_status_protected_24dp.xml
Normal file
30
res/drawable-night/ic_battery_status_protected_24dp.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:name="vector"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:name="path_1"
|
||||||
|
android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
</vector>
|
30
res/drawable/ic_battery_status_protected_24dp.xml
Normal file
30
res/drawable/ic_battery_status_protected_24dp.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:name="vector"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="16dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="16">
|
||||||
|
<path
|
||||||
|
android:name="path"
|
||||||
|
android:pathData="M 11.739 14.409 C 11.572 14.576 11.346 14.67 11.11 14.67 L 4.89 14.67 C 4.654 14.67 4.428 14.576 4.261 14.409 C 4.094 14.242 4 14.016 4 13.78 L 4 3.55 C 4 3.316 4.092 3.091 4.257 2.924 C 4.422 2.758 4.646 2.663 4.88 2.66 L 6.33 2.66 L 6.33 1.33 L 9.66 1.33 L 9.66 2.66 L 11.11 2.66 C 11.227 2.66 11.343 2.683 11.451 2.728 C 11.559 2.773 11.657 2.838 11.739 2.921 C 11.822 3.003 11.887 3.102 11.932 3.209 C 11.977 3.317 12 3.433 12 3.55 L 12 13.78 C 12 14.016 11.906 14.242 11.739 14.409 Z M 6 9 L 8.67 4 L 8.67 7.67 L 10 7.67 L 7.33 12.67 L 7.33 9 L 6 9 Z"
|
||||||
|
android:fillColor="#000000"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
</vector>
|
@@ -6416,8 +6416,18 @@
|
|||||||
<string name="battery_tip_limited_temporarily_title">Charging is paused</string>
|
<string name="battery_tip_limited_temporarily_title">Charging is paused</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">Protecting battery to extend battery lifespan</string>
|
<string name="battery_tip_limited_temporarily_summary">Protecting battery to extend battery lifespan</string>
|
||||||
<!-- Summary for the battery limited temporarily extra tip [CHAR LIMIT=NONE] -->
|
<!-- Title for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
|
||||||
<string name="battery_tip_limited_temporarily_extra_summary"><xliff:g id="percent" example="10%">%1$s</xliff:g></string>
|
<string name="battery_tip_dock_defender_future_bypass_title">Charging to <xliff:g id="percent" example="10%">%1$s</xliff:g> to protect the battery</string>
|
||||||
|
<!-- Summary for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_dock_defender_future_bypass_summary">When your tablet is docked, charging will be paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> to extend battery lifespan</string>
|
||||||
|
<!-- Title for the battery dock defender active tip [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_dock_defender_active_title">Charging paused to protect battery</string>
|
||||||
|
<!-- Summary for the battery dock defender active tip [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_dock_defender_active_summary">When your tablet is docked, charging is paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> to extend battery lifespan</string>
|
||||||
|
<!-- Title for the battery dock defender temporarily bypassed tip [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_dock_defender_temporarily_bypassed_title">Charging to full</string>
|
||||||
|
<!-- Summary for the battery dock defender temporarily bypassed tip [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="battery_tip_dock_defender_temporarily_bypassed_summary">To protect your battery, charging will be paused at <xliff:g id="percent" example="10%">%1$s</xliff:g> the next time your tablet is docked</string>
|
||||||
<!-- Content description for the battery limited temporarily tip secondary button [CHAR LIMIT=NONE] -->
|
<!-- Content description for the battery limited temporarily tip secondary button [CHAR LIMIT=NONE] -->
|
||||||
<string name="battery_tip_limited_temporarily_sec_button_content_description">Learn more about charging is paused</string>
|
<string name="battery_tip_limited_temporarily_sec_button_content_description">Learn more about charging is paused</string>
|
||||||
<!-- Text of battery limited temporarily tip resume charge button. [CHAR LIMIT=NONE] -->
|
<!-- Text of battery limited temporarily tip resume charge button. [CHAR LIMIT=NONE] -->
|
||||||
|
@@ -98,6 +98,7 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
|
|||||||
final IntentFilter intentFilter = new IntentFilter();
|
final IntentFilter intentFilter = new IntentFilter();
|
||||||
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||||
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
|
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
|
||||||
|
intentFilter.addAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
|
||||||
|
|
||||||
final Intent intent = mContext.registerReceiver(this, intentFilter);
|
final Intent intent = mContext.registerReceiver(this, intentFilter);
|
||||||
updateBatteryStatus(intent, true /* forceUpdate */);
|
updateBatteryStatus(intent, true /* forceUpdate */);
|
||||||
@@ -132,6 +133,8 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
|
|||||||
mBatteryHealth = batteryHealth;
|
mBatteryHealth = batteryHealth;
|
||||||
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
|
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
|
||||||
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
|
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
|
||||||
|
} else if (BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION.equals(intent.getAction())) {
|
||||||
|
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -42,6 +42,8 @@ import com.android.settingslib.fuelgauge.EstimateKt;
|
|||||||
import com.android.settingslib.utils.PowerUtil;
|
import com.android.settingslib.utils.PowerUtil;
|
||||||
import com.android.settingslib.utils.StringUtil;
|
import com.android.settingslib.utils.StringUtil;
|
||||||
|
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
|
||||||
public class BatteryInfo {
|
public class BatteryInfo {
|
||||||
private static final String TAG = "BatteryInfo";
|
private static final String TAG = "BatteryInfo";
|
||||||
|
|
||||||
@@ -49,6 +51,7 @@ public class BatteryInfo {
|
|||||||
public CharSequence remainingLabel;
|
public CharSequence remainingLabel;
|
||||||
public int batteryLevel;
|
public int batteryLevel;
|
||||||
public int batteryStatus;
|
public int batteryStatus;
|
||||||
|
public int pluggedStatus;
|
||||||
public boolean discharging = true;
|
public boolean discharging = true;
|
||||||
public boolean isOverheated;
|
public boolean isOverheated;
|
||||||
public long remainingTimeUs = 0;
|
public long remainingTimeUs = 0;
|
||||||
@@ -253,7 +256,8 @@ public class BatteryInfo {
|
|||||||
info.mBatteryUsageStats = batteryUsageStats;
|
info.mBatteryUsageStats = batteryUsageStats;
|
||||||
info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
|
info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
|
||||||
info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
|
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.averageTimeToDischarge = estimate.getAverageDischargeTime();
|
||||||
info.isOverheated = batteryBroadcast.getIntExtra(
|
info.isOverheated = batteryBroadcast.getIntExtra(
|
||||||
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
|
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
|
||||||
@@ -280,25 +284,37 @@ public class BatteryInfo {
|
|||||||
BatteryManager.BATTERY_STATUS_UNKNOWN);
|
BatteryManager.BATTERY_STATUS_UNKNOWN);
|
||||||
info.discharging = false;
|
info.discharging = false;
|
||||||
info.suggestionLabel = null;
|
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;
|
info.remainingLabel = null;
|
||||||
int chargingLimitedResId = R.string.power_charging_limited;
|
int chargingLimitedResId = R.string.power_charging_limited;
|
||||||
info.chargeLabel =
|
info.chargeLabel = context.getString(chargingLimitedResId, info.batteryPercentString);
|
||||||
context.getString(chargingLimitedResId, info.batteryPercentString);
|
} else if ((chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL
|
||||||
} 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);
|
info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
|
||||||
final CharSequence timeString = StringUtil.formatElapsedTime(
|
final CharSequence timeString = StringUtil.formatElapsedTime(context,
|
||||||
context,
|
(double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */,
|
||||||
PowerUtil.convertUsToMs(info.remainingTimeUs),
|
|
||||||
false /* withSeconds */,
|
|
||||||
true /* collapseTimeUnit */);
|
true /* collapseTimeUnit */);
|
||||||
int resId = R.string.power_charging_duration;
|
int resId = R.string.power_charging_duration;
|
||||||
info.remainingLabel = context.getString(
|
info.remainingLabel = context.getString(R.string.power_remaining_charging_duration_only,
|
||||||
R.string.power_remaining_charging_duration_only, timeString);
|
timeString);
|
||||||
info.chargeLabel = context.getString(resId, info.batteryPercentString, 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 {
|
} else {
|
||||||
final String chargeStatusLabel =
|
final String chargeStatusLabel = Utils.getBatteryStatus(context, batteryBroadcast,
|
||||||
Utils.getBatteryStatus(context, batteryBroadcast, compactStatus);
|
compactStatus);
|
||||||
info.remainingLabel = null;
|
info.remainingLabel = null;
|
||||||
info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
|
info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
|
||||||
resources.getString(R.string.power_charging, info.batteryPercentString,
|
resources.getString(R.string.power_charging, info.batteryPercentString,
|
||||||
|
@@ -24,6 +24,7 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ResolveInfo;
|
import android.content.pm.ResolveInfo;
|
||||||
import android.os.BatteryConsumer;
|
import android.os.BatteryConsumer;
|
||||||
|
import android.os.BatteryManager;
|
||||||
import android.os.BatteryStats;
|
import android.os.BatteryStats;
|
||||||
import android.os.BatteryStatsManager;
|
import android.os.BatteryStatsManager;
|
||||||
import android.os.BatteryUsageStats;
|
import android.os.BatteryUsageStats;
|
||||||
@@ -33,6 +34,7 @@ import android.os.Process;
|
|||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.UidBatteryConsumer;
|
import android.os.UidBatteryConsumer;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
@@ -72,6 +74,11 @@ public class BatteryUtils {
|
|||||||
/** Special UID for aggregated other users. */
|
/** Special UID for aggregated other users. */
|
||||||
public static final long UID_OTHER_USERS = Long.MIN_VALUE;
|
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)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({StatusType.SCREEN_USAGE,
|
@IntDef({StatusType.SCREEN_USAGE,
|
||||||
StatusType.FOREGROUND,
|
StatusType.FOREGROUND,
|
||||||
@@ -85,6 +92,18 @@ public class BatteryUtils {
|
|||||||
int ALL = 3;
|
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 final String TAG = "BatteryUtils";
|
||||||
|
|
||||||
private static BatteryUtils sInstance;
|
private static BatteryUtils sInstance;
|
||||||
@@ -570,4 +589,21 @@ public class BatteryUtils {
|
|||||||
|
|
||||||
return -1L;
|
return -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -147,7 +147,7 @@ public interface PowerUsageFeatureProvider {
|
|||||||
/**
|
/**
|
||||||
* Gets a intent for one time bypass charge limited to resume charging.
|
* Gets a intent for one time bypass charge limited to resume charging.
|
||||||
*/
|
*/
|
||||||
Intent getResumeChargeIntent();
|
Intent getResumeChargeIntent(boolean isDockDefender);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns battery history data with corresponding timestamp key.
|
* Returns battery history data with corresponding timestamp key.
|
||||||
|
@@ -156,7 +156,7 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Intent getResumeChargeIntent() {
|
public Intent getResumeChargeIntent(boolean isDockDefender) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -24,6 +24,7 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import com.android.settings.fuelgauge.BatteryInfo;
|
import com.android.settings.fuelgauge.BatteryInfo;
|
||||||
import com.android.settings.fuelgauge.BatteryUtils;
|
import com.android.settings.fuelgauge.BatteryUtils;
|
||||||
import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
|
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.EarlyWarningDetector;
|
||||||
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
|
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
|
||||||
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
|
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
|
||||||
@@ -74,6 +75,7 @@ public class BatteryTipLoader extends AsyncLoaderCompat<List<BatteryTip>> {
|
|||||||
tips.add(new EarlyWarningDetector(policy, context).detect());
|
tips.add(new EarlyWarningDetector(policy, context).detect());
|
||||||
tips.add(new BatteryDefenderDetector(
|
tips.add(new BatteryDefenderDetector(
|
||||||
batteryInfo, context.getApplicationContext()).detect());
|
batteryInfo, context.getApplicationContext()).detect());
|
||||||
|
tips.add(new DockDefenderDetector(batteryInfo, context.getApplicationContext()).detect());
|
||||||
Collections.sort(tips);
|
Collections.sort(tips);
|
||||||
return tips;
|
return tips;
|
||||||
}
|
}
|
||||||
|
@@ -37,11 +37,10 @@ public class BatteryDefenderDetector implements BatteryTipDetector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BatteryTip detect() {
|
public BatteryTip detect() {
|
||||||
if (mBatteryInfo.isOverheated) {
|
if (mBatteryInfo.isOverheated && !FeatureFactory.getFactory(mContext)
|
||||||
final boolean extraDefend = FeatureFactory.getFactory(mContext)
|
.getPowerUsageFeatureProvider(mContext)
|
||||||
.getPowerUsageFeatureProvider(mContext)
|
.isExtraDefend()) {
|
||||||
.isExtraDefend();
|
return new BatteryDefenderTip(BatteryTip.StateType.NEW);
|
||||||
return new BatteryDefenderTip(BatteryTip.StateType.NEW, extraDefend);
|
|
||||||
}
|
}
|
||||||
return new BatteryDefenderTip(BatteryTip.StateType.INVISIBLE);
|
return new BatteryDefenderTip(BatteryTip.StateType.INVISIBLE);
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -32,24 +32,15 @@ import com.android.settings.widget.CardPreference;
|
|||||||
import com.android.settingslib.HelpUtils;
|
import com.android.settingslib.HelpUtils;
|
||||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tip to show current battery is overheated
|
* Tip to show current battery is overheated
|
||||||
*/
|
*/
|
||||||
public class BatteryDefenderTip extends BatteryTip {
|
public class BatteryDefenderTip extends BatteryTip {
|
||||||
|
|
||||||
private static final String TAG = "BatteryDefenderTip";
|
private static final String TAG = "BatteryDefenderTip";
|
||||||
private boolean mExtraDefend = false;
|
|
||||||
|
|
||||||
public BatteryDefenderTip(@StateType int state) {
|
public BatteryDefenderTip(@StateType int state) {
|
||||||
this(state, false);
|
super(TipType.BATTERY_DEFENDER, state, false /* showDialog */);
|
||||||
}
|
|
||||||
|
|
||||||
public BatteryDefenderTip(@StateType int state, boolean extraDefend) {
|
|
||||||
super(TipType.BATTERY_DEFENDER, state, true /* showDialog */);
|
|
||||||
mExtraDefend = extraDefend;
|
|
||||||
mShowDialog = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BatteryDefenderTip(Parcel in) {
|
private BatteryDefenderTip(Parcel in) {
|
||||||
@@ -63,14 +54,6 @@ public class BatteryDefenderTip extends BatteryTip {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getSummary(Context context) {
|
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);
|
return context.getString(R.string.battery_tip_limited_temporarily_summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +114,7 @@ public class BatteryDefenderTip extends BatteryTip {
|
|||||||
final Intent intent =
|
final Intent intent =
|
||||||
FeatureFactory.getFactory(context)
|
FeatureFactory.getFactory(context)
|
||||||
.getPowerUsageFeatureProvider(context)
|
.getPowerUsageFeatureProvider(context)
|
||||||
.getResumeChargeIntent();
|
.getResumeChargeIntent(false);
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
context.sendBroadcast(intent);
|
context.sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
@@ -58,7 +58,8 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
|
|||||||
TipType.REDUCED_BATTERY,
|
TipType.REDUCED_BATTERY,
|
||||||
TipType.LOW_BATTERY,
|
TipType.LOW_BATTERY,
|
||||||
TipType.REMOVE_APP_RESTRICTION,
|
TipType.REMOVE_APP_RESTRICTION,
|
||||||
TipType.BATTERY_DEFENDER})
|
TipType.BATTERY_DEFENDER,
|
||||||
|
TipType.DOCK_DEFENDER})
|
||||||
public @interface TipType {
|
public @interface TipType {
|
||||||
int SMART_BATTERY_MANAGER = 0;
|
int SMART_BATTERY_MANAGER = 0;
|
||||||
int APP_RESTRICTION = 1;
|
int APP_RESTRICTION = 1;
|
||||||
@@ -69,6 +70,7 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
|
|||||||
int SUMMARY = 6;
|
int SUMMARY = 6;
|
||||||
int REMOVE_APP_RESTRICTION = 7;
|
int REMOVE_APP_RESTRICTION = 7;
|
||||||
int BATTERY_DEFENDER = 8;
|
int BATTERY_DEFENDER = 8;
|
||||||
|
int DOCK_DEFENDER = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -78,12 +80,13 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
|
|||||||
TIP_ORDER.append(TipType.BATTERY_SAVER, 0);
|
TIP_ORDER.append(TipType.BATTERY_SAVER, 0);
|
||||||
TIP_ORDER.append(TipType.LOW_BATTERY, 1);
|
TIP_ORDER.append(TipType.LOW_BATTERY, 1);
|
||||||
TIP_ORDER.append(TipType.BATTERY_DEFENDER, 2);
|
TIP_ORDER.append(TipType.BATTERY_DEFENDER, 2);
|
||||||
TIP_ORDER.append(TipType.APP_RESTRICTION, 3);
|
TIP_ORDER.append(TipType.DOCK_DEFENDER, 3);
|
||||||
TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 4);
|
TIP_ORDER.append(TipType.APP_RESTRICTION, 4);
|
||||||
TIP_ORDER.append(TipType.SUMMARY, 5);
|
TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 5);
|
||||||
TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 6);
|
TIP_ORDER.append(TipType.SUMMARY, 6);
|
||||||
TIP_ORDER.append(TipType.REDUCED_BATTERY, 7);
|
TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 7);
|
||||||
TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 8);
|
TIP_ORDER.append(TipType.REDUCED_BATTERY, 8);
|
||||||
|
TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String KEY_PREFIX = "key_battery_tip";
|
private static final String KEY_PREFIX = "key_battery_tip";
|
||||||
|
@@ -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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@@ -55,6 +55,7 @@ public class BatteryBroadcastReceiverTest {
|
|||||||
private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
|
private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private Intent mChargingIntent;
|
private Intent mChargingIntent;
|
||||||
|
private Intent mDockDefenderBypassIntent;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -72,6 +73,8 @@ public class BatteryBroadcastReceiverTest {
|
|||||||
mChargingIntent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_INTENT_SCALE);
|
mChargingIntent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_INTENT_SCALE);
|
||||||
mChargingIntent
|
mChargingIntent
|
||||||
.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
|
.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_CHARGING);
|
||||||
|
mDockDefenderBypassIntent = new Intent(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -130,6 +133,13 @@ public class BatteryBroadcastReceiverTest {
|
|||||||
verify(mBatteryListener, never()).onBatteryChanged(anyInt());
|
verify(mBatteryListener, never()).onBatteryChanged(anyInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnReceive_dockDefenderBypassed_listenerInvoked() {
|
||||||
|
mBatteryBroadcastReceiver.onReceive(mContext, mDockDefenderBypassIntent);
|
||||||
|
|
||||||
|
verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegister_updateBatteryStatus() {
|
public void testRegister_updateBatteryStatus() {
|
||||||
doReturn(mChargingIntent).when(mContext).registerReceiver(any(), any());
|
doReturn(mChargingIntent).when(mContext).registerReceiver(any(), any());
|
||||||
|
@@ -36,6 +36,7 @@ import android.os.BatteryManager;
|
|||||||
import android.os.BatteryStats;
|
import android.os.BatteryStats;
|
||||||
import android.os.BatteryUsageStats;
|
import android.os.BatteryUsageStats;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.provider.Settings;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
import com.android.internal.os.BatteryStatsHistoryIterator;
|
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_NO_TIME = "50% - charging";
|
||||||
private static final String STATUS_CHARGING_TIME = "50% - 0 min left until full";
|
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_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_NULL = -1;
|
||||||
private static final long REMAINING_TIME = 2;
|
private static final long REMAINING_TIME = 2;
|
||||||
// Strings are defined in frameworks/base/packages/SettingsLib/res/values/strings.xml
|
// Strings are defined in frameworks/base/packages/SettingsLib/res/values/strings.xml
|
||||||
@@ -97,6 +99,10 @@ public class BatteryInfoTest {
|
|||||||
mDisChargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent();
|
mDisChargingBatteryBroadcast = BatteryTestUtils.getDischargingIntent();
|
||||||
|
|
||||||
mChargingBatteryBroadcast = BatteryTestUtils.getChargingIntent();
|
mChargingBatteryBroadcast = BatteryTestUtils.getChargingIntent();
|
||||||
|
|
||||||
|
doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
|
||||||
|
Settings.Global.putInt(mContext.getContentResolver(),
|
||||||
|
BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -231,6 +237,7 @@ public class BatteryInfoTest {
|
|||||||
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
|
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
|
||||||
mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
|
mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
|
||||||
false /* shortString */);
|
false /* shortString */);
|
||||||
|
|
||||||
assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING);
|
assertThat(info.remainingTimeUs).isEqualTo(TEST_CHARGE_TIME_REMAINING);
|
||||||
assertThat(info.remainingLabel.toString())
|
assertThat(info.remainingLabel.toString())
|
||||||
.isEqualTo(TEST_CHARGE_TIME_REMAINING_STRINGIFIED);
|
.isEqualTo(TEST_CHARGE_TIME_REMAINING_STRINGIFIED);
|
||||||
@@ -265,6 +272,62 @@ public class BatteryInfoTest {
|
|||||||
assertThat(info.chargeLabel.toString()).contains(expectedString);
|
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.
|
// Make our battery stats return a sequence of battery events.
|
||||||
private void mockBatteryStatsHistory() {
|
private void mockBatteryStatsHistory() {
|
||||||
// Mock out new data every time iterateBatteryStatsHistory is called.
|
// Mock out new data every time iterateBatteryStatsHistory is called.
|
||||||
|
@@ -132,7 +132,12 @@ public class PowerUsageFeatureProviderImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetResumeChargeIntent_returnNull() {
|
public void testGetResumeChargeIntentWithoutDockDefender_returnNull() {
|
||||||
assertThat(mPowerFeatureProvider.getResumeChargeIntent()).isNull();
|
assertThat(mPowerFeatureProvider.getResumeChargeIntent(false)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetResumeChargeIntentWithDockDefender_returnNull() {
|
||||||
|
assertThat(mPowerFeatureProvider.getResumeChargeIntent(true)).isNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -53,6 +53,7 @@ public class BatteryTipLoaderTest {
|
|||||||
BatteryTip.TipType.BATTERY_SAVER,
|
BatteryTip.TipType.BATTERY_SAVER,
|
||||||
BatteryTip.TipType.LOW_BATTERY,
|
BatteryTip.TipType.LOW_BATTERY,
|
||||||
BatteryTip.TipType.BATTERY_DEFENDER,
|
BatteryTip.TipType.BATTERY_DEFENDER,
|
||||||
|
BatteryTip.TipType.DOCK_DEFENDER,
|
||||||
BatteryTip.TipType.HIGH_DEVICE_USAGE,
|
BatteryTip.TipType.HIGH_DEVICE_USAGE,
|
||||||
BatteryTip.TipType.SMART_BATTERY_MANAGER};
|
BatteryTip.TipType.SMART_BATTERY_MANAGER};
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
|
@@ -18,10 +18,15 @@ package com.android.settings.fuelgauge.batterytip.detectors;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
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 androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import com.android.settings.fuelgauge.BatteryInfo;
|
import com.android.settings.fuelgauge.BatteryInfo;
|
||||||
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
|
||||||
|
import com.android.settings.testutils.FakeFeatureFactory;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -36,6 +41,9 @@ public class BatteryDefenderDetectorTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private BatteryInfo mBatteryInfo;
|
private BatteryInfo mBatteryInfo;
|
||||||
private BatteryDefenderDetector mBatteryDefenderDetector;
|
private BatteryDefenderDetector mBatteryDefenderDetector;
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
private FakeFeatureFactory mFakeFeatureFactory;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -43,20 +51,42 @@ public class BatteryDefenderDetectorTest {
|
|||||||
|
|
||||||
mBatteryInfo.discharging = false;
|
mBatteryInfo.discharging = false;
|
||||||
|
|
||||||
|
mContext = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
mBatteryDefenderDetector = new BatteryDefenderDetector(
|
mBatteryDefenderDetector = new BatteryDefenderDetector(
|
||||||
mBatteryInfo, ApplicationProvider.getApplicationContext());
|
mBatteryInfo, mContext);
|
||||||
|
|
||||||
|
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDetect_notOverheated_tipInvisible() {
|
public void testDetect_notOverheatedNotExtraDefend_tipInvisible() {
|
||||||
mBatteryInfo.isOverheated = false;
|
mBatteryInfo.isOverheated = false;
|
||||||
|
when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
|
||||||
|
|
||||||
assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
|
assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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;
|
mBatteryInfo.isOverheated = true;
|
||||||
|
when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
|
||||||
|
|
||||||
assertThat(mBatteryDefenderDetector.detect().getState())
|
assertThat(mBatteryDefenderDetector.detect().getState())
|
||||||
.isEqualTo(BatteryTip.StateType.NEW);
|
.isEqualTo(BatteryTip.StateType.NEW);
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
@@ -79,19 +79,11 @@ public class BatteryDefenderTipTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getSummary_notExtraDefended_showNonExtraDefendedSummary() {
|
public void getSummary_showSummary() {
|
||||||
assertThat(mBatteryDefenderTip.getSummary(mContext))
|
assertThat(mBatteryDefenderTip.getSummary(mContext))
|
||||||
.isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_summary));
|
.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
|
@Test
|
||||||
public void getIcon_showIcon() {
|
public void getIcon_showIcon() {
|
||||||
assertThat(mBatteryDefenderTip.getIconId())
|
assertThat(mBatteryDefenderTip.getIconId())
|
||||||
|
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -37,7 +37,7 @@ public class BatteryTestUtils {
|
|||||||
BatteryManager.BATTERY_STATUS_DISCHARGING);
|
BatteryManager.BATTERY_STATUS_DISCHARGING);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 intent = new Intent();
|
||||||
intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged);
|
intent.putExtra(BatteryManager.EXTRA_PLUGGED, plugged);
|
||||||
intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
|
intent.putExtra(BatteryManager.EXTRA_LEVEL, level);
|
||||||
|
Reference in New Issue
Block a user