Merge "Refactor background optimization mode in Power Usage Detail page." into main
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0dae688..1eb58ee 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5434,6 +5434,10 @@
<!-- Category title for battery background settings in power usage detail page [CHAR LIMIT=NONE] -->
<string name="manager_battery_usage_category_title">Manage battery usage</string>
+ <!-- Title for allow background usage [CHAR LIMIT=NONE] -->
+ <string name="manager_battery_usage_allow_background_usage_title">Allow background usage</string>
+ <!-- Summary for allow background usage [CHAR LIMIT=NONE] -->
+ <string name="manager_battery_usage_allow_background_usage_summary">Enable for real-time updates, disable to save battery</string>
<!-- Title for the battery unrestricted settings [CHAR_LIMIT=40] -->
<string name="manager_battery_usage_unrestricted_title">Unrestricted</string>
<!-- Title for the battery optimized settings [CHAR_LIMIT=40] -->
diff --git a/res/xml/power_background_usage_detail.xml b/res/xml/power_background_usage_detail.xml
new file mode 100644
index 0000000..fb089fd
--- /dev/null
+++ b/res/xml/power_background_usage_detail.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2023 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.
+ -->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:title="@string/manager_battery_usage_allow_background_usage_title">
+
+ <com.android.settingslib.widget.LayoutPreference
+ android:key="header_view"
+ android:layout="@layout/settings_entity_header"
+ android:selectable="false"/>
+
+ <com.android.settingslib.widget.MainSwitchPreference
+ android:key="allow_background_usage"
+ android:title="@string/manager_battery_usage_allow_background_usage_title"
+ settings:controller="com.android.settings.fuelgauge.AllowBackgroundPreferenceController"/>
+
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="optimized_preference"
+ android:title="@string/manager_battery_usage_optimized_title"
+ android:summary="@string/manager_battery_usage_optimized_summary"
+ settings:controller="com.android.settings.fuelgauge.OptimizedPreferenceController"/>
+
+ <com.android.settingslib.widget.SelectorWithWidgetPreference
+ android:key="unrestricted_preference"
+ android:title="@string/manager_battery_usage_unrestricted_title"
+ android:summary="@string/manager_battery_usage_unrestricted_summary"
+ settings:controller="com.android.settings.fuelgauge.UnrestrictedPreferenceController"/>
+
+ <com.android.settingslib.widget.FooterPreference
+ android:key="app_usage_footer_preference"
+ android:title="@string/manager_battery_usage_footer"
+ android:selectable="false"
+ settings:searchable="false"/>
+</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/power_usage_detail.xml b/res/xml/power_usage_detail.xml
index 7b92f99..f3b30b6 100644
--- a/res/xml/power_usage_detail.xml
+++ b/res/xml/power_usage_detail.xml
@@ -50,30 +50,11 @@
android:title="@string/manager_battery_usage_category_title"
android:key="manage_battery_usage_category">
- <com.android.settingslib.widget.SelectorWithWidgetPreference
- android:key="unrestricted_pref"
- android:summary="@string/manager_battery_usage_unrestricted_summary"
- android:title="@string/manager_battery_usage_unrestricted_title"
- settings:controller="com.android.settings.fuelgauge.UnrestrictedPreferenceController"/>
-
- <com.android.settingslib.widget.SelectorWithWidgetPreference
- android:key="optimized_pref"
- android:summary="@string/manager_battery_usage_optimized_summary"
- android:title="@string/manager_battery_usage_optimized_title"
- settings:controller="com.android.settings.fuelgauge.OptimizedPreferenceController"/>
-
- <com.android.settingslib.widget.SelectorWithWidgetPreference
- android:key="restricted_pref"
- android:summary="@string/manager_battery_usage_restricted_summary"
- android:title="@string/manager_battery_usage_restricted_title"
- settings:controller="com.android.settings.fuelgauge.RestrictedPreferenceController"/>
+ <com.android.settingslib.PrimarySwitchPreference
+ android:key="allow_background_usage"
+ android:title="@string/manager_battery_usage_allow_background_usage_title"
+ settings:controller="com.android.settings.fuelgauge.AllowBackgroundPreferenceController"/>
</PreferenceCategory>
- <com.android.settingslib.widget.FooterPreference
- android:key="app_usage_footer_preference"
- android:title="@string/manager_battery_usage_footer"
- android:selectable="false"
- settings:searchable="false"/>
-
</PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index 82917d2..5262ba9 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -27,10 +27,13 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.Log;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
@@ -45,14 +48,12 @@
import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.EntityHeaderController;
-import com.android.settingslib.HelpUtils;
+import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.LayoutPreference;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
import java.util.List;
@@ -67,8 +68,8 @@
*/
public class AdvancedPowerUsageDetail extends DashboardFragment implements
ButtonActionDialogFragment.AppButtonsDialogListener,
- SelectorWithWidgetPreference.OnClickListener {
-
+ Preference.OnPreferenceClickListener,
+ Preference.OnPreferenceChangeListener {
public static final String TAG = "AdvancedPowerDetail";
public static final String EXTRA_UID = "extra_uid";
public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
@@ -85,19 +86,16 @@
public static final String EXTRA_POWER_USAGE_AMOUNT = "extra_power_usage_amount";
private static final String KEY_PREF_HEADER = "header_view";
- private static final String KEY_PREF_UNRESTRICTED = "unrestricted_pref";
- private static final String KEY_PREF_OPTIMIZED = "optimized_pref";
- private static final String KEY_PREF_RESTRICTED = "restricted_pref";
- private static final String KEY_FOOTER_PREFERENCE = "app_usage_footer_preference";
- private static final String PACKAGE_NAME_NONE = "none";
-
- private static final String HEADER_SUMMARY_FORMAT = "%s\n(%s)";
+ private static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
private static final int REQUEST_UNINSTALL = 0;
private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+ private AppButtonsPreferenceController mAppButtonsPreferenceController;
+ private PowerUsageTimeController mPowerUsageTimeController;
+
@VisibleForTesting
LayoutPreference mHeaderPreference;
@VisibleForTesting
@@ -107,13 +105,7 @@
@VisibleForTesting
BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting
- FooterPreference mFooterPreference;
- @VisibleForTesting
- SelectorWithWidgetPreference mRestrictedPreference;
- @VisibleForTesting
- SelectorWithWidgetPreference mOptimizePreference;
- @VisibleForTesting
- SelectorWithWidgetPreference mUnrestrictedPreference;
+ PrimarySwitchPreference mAllowBackgroundUsagePreference;
@VisibleForTesting
@BatteryOptimizeUtils.OptimizationMode
int mOptimizationMode = BatteryOptimizeUtils.MODE_UNKNOWN;
@@ -122,9 +114,6 @@
@VisibleForTesting
StringBuilder mLogStringBuilder;
- private AppButtonsPreferenceController mAppButtonsPreferenceController;
- private PowerUsageTimeController mPowerUsageTimeController;
-
// A wrapper class to carry LaunchBatteryDetailPage required arguments.
private static final class LaunchBatteryDetailPageArgs {
private String mUsagePercent;
@@ -209,7 +198,7 @@
args.putString(EXTRA_ANOMALY_HINT_PREF_KEY, launchArgs.mAnomalyHintPrefKey);
args.putString(EXTRA_ANOMALY_HINT_TEXT, launchArgs.mAnomalyHintText);
final int userId = launchArgs.mIsUserEntry ? ActivityManager.getCurrentUser()
- : UserHandle.getUserId(launchArgs.mUid);
+ : UserHandle.getUserId(launchArgs.mUid);
new SubSettingLauncher(context)
.setDestination(AdvancedPowerUsageDetail.class.getName())
@@ -257,7 +246,7 @@
super.onCreate(icicle);
final String packageName = getArguments().getString(EXTRA_PACKAGE_NAME);
- onCreateForTriState(packageName);
+ onCreateBackgroundUsageState(packageName);
mHeaderPreference = findPreference(KEY_PREF_HEADER);
if (packageName != null) {
@@ -271,10 +260,10 @@
initHeader();
mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode();
- initPreferenceForTriState(getContext());
+ initFooter();
mExecutor.execute(() -> {
- String packageName =
- getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
+ final String packageName = BatteryUtils
+ .getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(
getContext(),
@@ -288,11 +277,10 @@
public void onPause() {
super.onPause();
- final int selectedPreference = getSelectedPreference();
-
notifyBackupManager();
- mLogStringBuilder.append(", onPause mode = ").append(selectedPreference);
- logMetricCategory(selectedPreference);
+ final int currentOptimizeMode = mBatteryOptimizeUtils.getAppOptimizationMode();
+ mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
+ logMetricCategory(currentOptimizeMode);
mExecutor.execute(() -> {
BatteryOptimizeLogUtils.writeLog(
@@ -302,7 +290,7 @@
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
mLogStringBuilder.toString());
});
- Log.d(TAG, "Leave with mode: " + selectedPreference);
+ Log.d(TAG, "Leave with mode: " + currentOptimizeMode);
}
@VisibleForTesting
@@ -353,33 +341,28 @@
}
@VisibleForTesting
- void initPreferenceForTriState(Context context) {
+ void initFooter() {
final String stateString;
- final String footerString;
+ final String detailInfoString;
+ final Context context = getContext();
if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
// Present optimized only string when the package name is invalid.
stateString = context.getString(R.string.manager_battery_usage_optimized_only);
- footerString = context.getString(
- R.string.manager_battery_usage_footer_limited, stateString);
+ detailInfoString =
+ context.getString(R.string.manager_battery_usage_footer_limited, stateString);
} else if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
// Present unrestricted only string when the package is system or default active app.
stateString = context.getString(R.string.manager_battery_usage_unrestricted_only);
- footerString = context.getString(
- R.string.manager_battery_usage_footer_limited, stateString);
+ detailInfoString =
+ context.getString(R.string.manager_battery_usage_footer_limited, stateString);
} else {
// Present default string to normal app.
- footerString = context.getString(R.string.manager_battery_usage_footer);
+ detailInfoString =
+ context.getString(
+ R.string.manager_battery_usage_allow_background_usage_summary);
}
- mFooterPreference.setTitle(footerString);
- final Intent helpIntent = HelpUtils.getHelpIntent(context, context.getString(
- R.string.help_url_app_usage_settings), /*backupContext=*/ "");
- if (helpIntent != null) {
- mFooterPreference.setLearnMoreAction(v ->
- startActivityForResult(helpIntent, /*requestCode=*/ 0));
- mFooterPreference.setLearnMoreText(
- context.getString(R.string.manager_battery_usage_link_a11y));
- }
+ mAllowBackgroundUsagePreference.setSummary(detailInfoString);
}
@Override
@@ -412,9 +395,7 @@
controllers.add(mPowerUsageTimeController);
}
controllers.add(mAppButtonsPreferenceController);
- controllers.add(new UnrestrictedPreferenceController(context, uid, packageName));
- controllers.add(new OptimizedPreferenceController(context, uid, packageName));
- controllers.add(new RestrictedPreferenceController(context, uid, packageName));
+ controllers.add(new AllowBackgroundPreferenceController(context, uid, packageName));
return controllers;
}
@@ -435,34 +416,45 @@
}
@Override
- public void onRadioButtonClicked(SelectorWithWidgetPreference selected) {
- final String selectedKey = selected.getKey();
- updatePreferenceState(mUnrestrictedPreference, selectedKey);
- updatePreferenceState(mOptimizePreference, selectedKey);
- updatePreferenceState(mRestrictedPreference, selectedKey);
- mBatteryOptimizeUtils.setAppUsageState(getSelectedPreference(), Action.APPLY);
+ public boolean onPreferenceClick(Preference preference) {
+ if (!(preference instanceof PrimarySwitchPreference)
+ || !TextUtils.equals(preference.getKey(), KEY_ALLOW_BACKGROUND_USAGE)) {
+ return false;
+ }
+ PowerBackgroundUsageDetail.startPowerBackgroundUsageDetailPage(
+ getContext(), getArguments());
+ return true;
}
- private void updatePreferenceState(SelectorWithWidgetPreference preference,
- String selectedKey) {
- preference.setChecked(selectedKey.equals(preference.getKey()));
+ @Override
+ public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
+ if (!(preference instanceof PrimarySwitchPreference)
+ || !TextUtils.equals(preference.getKey(), KEY_ALLOW_BACKGROUND_USAGE)) {
+ return false;
+ }
+ if (newValue instanceof Boolean) {
+ final boolean isAllowBackgroundUsage = (boolean) newValue;
+ mBatteryOptimizeUtils.setAppUsageState(
+ isAllowBackgroundUsage
+ ? BatteryOptimizeUtils.MODE_OPTIMIZED
+ : BatteryOptimizeUtils.MODE_RESTRICTED,
+ Action.APPLY);
+ }
+ return true;
}
- private void logMetricCategory(int selectedKey) {
- if (selectedKey == mOptimizationMode) {
+ private void logMetricCategory(int currentOptimizeMode) {
+ if (currentOptimizeMode == mOptimizationMode) {
return;
}
-
int metricCategory = 0;
- switch (selectedKey) {
+ switch (currentOptimizeMode) {
case BatteryOptimizeUtils.MODE_UNRESTRICTED:
- metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_UNRESTRICTED;
- break;
case BatteryOptimizeUtils.MODE_OPTIMIZED:
- metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_OPTIMIZED;
+ metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_ALLOW_BACKGROUND;
break;
case BatteryOptimizeUtils.MODE_RESTRICTED:
- metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_RESTRICTED;
+ metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_DISABLE_BACKGROUND;
break;
}
if (metricCategory == 0) {
@@ -470,8 +462,8 @@
}
int finalMetricCategory = metricCategory;
mExecutor.execute(() -> {
- String packageName =
- getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
+ String packageName = BatteryUtils
+ .getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(
/* attribution */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
@@ -482,33 +474,15 @@
});
}
- private void onCreateForTriState(String packageName) {
- mUnrestrictedPreference = findPreference(KEY_PREF_UNRESTRICTED);
- mOptimizePreference = findPreference(KEY_PREF_OPTIMIZED);
- mRestrictedPreference = findPreference(KEY_PREF_RESTRICTED);
- mFooterPreference = findPreference(KEY_FOOTER_PREFERENCE);
- mUnrestrictedPreference.setOnClickListener(this);
- mOptimizePreference.setOnClickListener(this);
- mRestrictedPreference.setOnClickListener(this);
-
- mBatteryOptimizeUtils = new BatteryOptimizeUtils(
- getContext(), getArguments().getInt(EXTRA_UID), packageName);
- }
-
- private int getSelectedPreference() {
- if (mRestrictedPreference.isChecked()) {
- return BatteryOptimizeUtils.MODE_RESTRICTED;
- } else if (mUnrestrictedPreference.isChecked()) {
- return BatteryOptimizeUtils.MODE_UNRESTRICTED;
- } else if (mOptimizePreference.isChecked()) {
- return BatteryOptimizeUtils.MODE_OPTIMIZED;
- } else {
- return BatteryOptimizeUtils.MODE_UNKNOWN;
+ private void onCreateBackgroundUsageState(String packageName) {
+ mAllowBackgroundUsagePreference = findPreference(KEY_ALLOW_BACKGROUND_USAGE);
+ if (mAllowBackgroundUsagePreference != null) {
+ mAllowBackgroundUsagePreference.setOnPreferenceClickListener(this);
+ mAllowBackgroundUsagePreference.setOnPreferenceChangeListener(this);
}
- }
- private static String getLoggingPackageName(Context context, String originalPackingName) {
- return BatteryUtils.isAppInstalledFromGooglePlayStore(context, originalPackingName)
- ? originalPackingName : PACKAGE_NAME_NONE;
+ mBatteryOptimizeUtils =
+ new BatteryOptimizeUtils(
+ getContext(), getArguments().getInt(EXTRA_UID), packageName);
}
}
diff --git a/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceController.java b/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceController.java
new file mode 100644
index 0000000..d722bad
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceController.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2023 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;
+
+import android.content.Context;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.PrimarySwitchPreference;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.MainSwitchPreference;
+
+/** Controller to update the app background usage state */
+public class AllowBackgroundPreferenceController extends AbstractPreferenceController
+ implements PreferenceControllerMixin {
+
+ private static final String TAG = "AllowBackgroundPreferenceController";
+
+ @VisibleForTesting static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
+
+ @VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
+
+ public AllowBackgroundPreferenceController(Context context, int uid, String packageName) {
+ super(context);
+ mBatteryOptimizeUtils = new BatteryOptimizeUtils(context, uid, packageName);
+ }
+
+ private void setChecked(Preference preference, boolean checked) {
+ if (preference instanceof PrimarySwitchPreference) {
+ ((PrimarySwitchPreference) preference).setChecked(checked);
+ } else if (preference instanceof MainSwitchPreference) {
+ ((MainSwitchPreference) preference).setChecked(checked);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ preference.setEnabled(mBatteryOptimizeUtils.isOptimizeModeMutable());
+
+ final boolean isAllowBackground = mBatteryOptimizeUtils.getAppOptimizationMode()
+ != BatteryOptimizeUtils.MODE_RESTRICTED;
+ setChecked(preference, isAllowBackground);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_ALLOW_BACKGROUND_USAGE;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ return getPreferenceKey().equals(preference.getKey());
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
index 7b3a6ad..003f771 100644
--- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
@@ -147,6 +147,22 @@
}
/**
+ * Return {@code true} if the optimization mode of this package can be changed
+ */
+ public boolean isOptimizeModeMutable() {
+ return !isDisabledForOptimizeModeOnly() && !isSystemOrDefaultApp();
+ }
+
+ /**
+ * Return {@code true} if the optimization mode is mutable and current state is not restricted
+ */
+ public boolean isSelectorPreferenceEnabled() {
+ // Enable the preference if apps are not set into restricted mode, otherwise disable it
+ return isOptimizeModeMutable()
+ && getAppOptimizationMode() != BatteryOptimizeUtils.MODE_RESTRICTED;
+ }
+
+ /**
* Gets the list of installed applications.
*/
public static ArraySet<ApplicationInfo> getInstalledApplications(
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 3b958ae..c38af07 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -88,6 +88,7 @@
public static final String BYPASS_DOCK_DEFENDER_ACTION = "battery.dock.defender.bypass";
private static final String GOOGLE_PLAY_STORE_PACKAGE = "com.android.vending";
+ private static final String PACKAGE_NAME_NONE = "none";
@Retention(RetentionPolicy.SOURCE)
@IntDef({StatusType.SCREEN_USAGE,
@@ -140,6 +141,12 @@
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
}
+ /** For test to reset single instance. */
+ @VisibleForTesting
+ public void reset() {
+ sInstance = null;
+ }
+
public long getProcessTimeMs(@StatusType int type, @Nullable BatteryStats.Uid uid,
int which) {
if (uid == null) {
@@ -616,6 +623,12 @@
&& GOOGLE_PLAY_STORE_PACKAGE.equals(installSourceInfo.getInitiatingPackageName());
}
+ /** Gets the logging package name. */
+ public static String getLoggingPackageName(Context context, String originalPackingName) {
+ return BatteryUtils.isAppInstalledFromGooglePlayStore(context, originalPackingName)
+ ? originalPackingName : PACKAGE_NAME_NONE;
+ }
+
/** Gets the latest sticky battery intent from the Android system. */
public static Intent getBatteryIntent(Context context) {
return com.android.settingslib.fuelgauge.BatteryUtils.getBatteryIntent(context);
diff --git a/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java b/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
index ca75b0e..3fed00c 100644
--- a/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
@@ -17,7 +17,6 @@
package com.android.settings.fuelgauge;
import android.content.Context;
-import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -31,8 +30,10 @@
private static final String TAG = "OPTIMIZED_PREF";
- @VisibleForTesting String KEY_OPTIMIZED_PREF = "optimized_pref";
- @VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
+ @VisibleForTesting
+ static final String KEY_OPTIMIZED_PREF = "optimized_preference";
+ @VisibleForTesting
+ BatteryOptimizeUtils mBatteryOptimizeUtils;
public OptimizedPreferenceController(Context context, int uid, String packageName) {
super(context);
@@ -46,24 +47,12 @@
@Override
public void updateState(Preference preference) {
- if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
- Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
- preference.setEnabled(true);
- ((SelectorWithWidgetPreference) preference).setChecked(true);
- return;
- }
+ preference.setEnabled(mBatteryOptimizeUtils.isSelectorPreferenceEnabled());
- if (mBatteryOptimizeUtils.getAppOptimizationMode()
- == BatteryOptimizeUtils.MODE_OPTIMIZED) {
- Log.d(TAG, "is optimized states");
- ((SelectorWithWidgetPreference) preference).setChecked(true);
- } else {
- ((SelectorWithWidgetPreference) preference).setChecked(false);
- if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
- Log.d(TAG, "is system or default app, disable pref");
- preference.setEnabled(false);
- }
- }
+ final boolean isOptimized = mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()
+ || mBatteryOptimizeUtils.getAppOptimizationMode()
+ == BatteryOptimizeUtils.MODE_OPTIMIZED;
+ ((SelectorWithWidgetPreference) preference).setChecked(isOptimized);
}
@Override
diff --git a/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java b/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java
new file mode 100644
index 0000000..3bf4562
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetail.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2023 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;
+
+
+import static com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
+
+import android.app.Activity;
+import android.app.backup.BackupManager;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.widget.Switch;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.HelpUtils;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.widget.FooterPreference;
+import com.android.settingslib.widget.LayoutPreference;
+import com.android.settingslib.widget.MainSwitchPreference;
+import com.android.settingslib.widget.OnMainSwitchChangeListener;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Allow background usage fragment for each app
+ */
+public class PowerBackgroundUsageDetail extends DashboardFragment implements
+ SelectorWithWidgetPreference.OnClickListener,
+ OnMainSwitchChangeListener {
+ private static final String TAG = "PowerBackgroundUsageDetail";
+
+ public static final String EXTRA_UID = "extra_uid";
+ public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
+ public static final String EXTRA_LABEL = "extra_label";
+ public static final String EXTRA_POWER_USAGE_AMOUNT = "extra_power_usage_amount";
+ public static final String EXTRA_ICON_ID = "extra_icon_id";
+ private static final String KEY_PREF_HEADER = "header_view";
+ private static final String KEY_PREF_UNRESTRICTED = "unrestricted_preference";
+ private static final String KEY_PREF_OPTIMIZED = "optimized_preference";
+ private static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
+ private static final String KEY_FOOTER_PREFERENCE = "app_usage_footer_preference";
+
+ private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+
+ @VisibleForTesting
+ LayoutPreference mHeaderPreference;
+ @VisibleForTesting
+ ApplicationsState mState;
+ @VisibleForTesting
+ ApplicationsState.AppEntry mAppEntry;
+ @VisibleForTesting
+ BatteryOptimizeUtils mBatteryOptimizeUtils;
+ @VisibleForTesting
+ SelectorWithWidgetPreference mOptimizePreference;
+ @VisibleForTesting
+ SelectorWithWidgetPreference mUnrestrictedPreference;
+ @VisibleForTesting
+ MainSwitchPreference mMainSwitchPreference;
+ @VisibleForTesting
+ FooterPreference mFooterPreference;
+ @VisibleForTesting
+ BackupManager mBackupManager;
+ @VisibleForTesting
+ StringBuilder mLogStringBuilder;
+ @VisibleForTesting
+ @BatteryOptimizeUtils.OptimizationMode
+ int mOptimizationMode = BatteryOptimizeUtils.MODE_UNKNOWN;
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+
+ mState = ApplicationsState.getInstance(getActivity().getApplication());
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final String packageName = getArguments().getString(EXTRA_PACKAGE_NAME);
+ onCreateBackgroundUsageState(packageName);
+ mHeaderPreference = findPreference(KEY_PREF_HEADER);
+
+ if (packageName != null) {
+ mAppEntry = mState.getEntry(packageName, UserHandle.myUserId());
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ initHeader();
+ mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode();
+ initFooter();
+ mExecutor.execute(() -> {
+ String packageName = BatteryUtils
+ .getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
+ FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
+ .action(
+ getContext(),
+ SettingsEnums.OPEN_APP_BATTERY_USAGE,
+ packageName);
+ });
+ mLogStringBuilder = new StringBuilder("onResume mode = ").append(mOptimizationMode);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+
+ notifyBackupManager();
+ final int currentOptimizeMode = mBatteryOptimizeUtils.getAppOptimizationMode();
+ mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
+ logMetricCategory(currentOptimizeMode);
+
+ mExecutor.execute(() -> {
+ BatteryOptimizeLogUtils.writeLog(
+ getContext().getApplicationContext(),
+ Action.LEAVE,
+ BatteryOptimizeLogUtils.getPackageNameWithUserId(
+ mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
+ mLogStringBuilder.toString());
+ });
+ Log.d(TAG, "Leave with mode: " + currentOptimizeMode);
+ }
+
+ @Override
+ public void onRadioButtonClicked(SelectorWithWidgetPreference selected) {
+ final String selectedKey = selected == null ? null : selected.getKey();
+ updateSelectorPreferenceState(mUnrestrictedPreference, selectedKey);
+ updateSelectorPreferenceState(mOptimizePreference, selectedKey);
+ mBatteryOptimizeUtils.setAppUsageState(getSelectedPreference(), Action.APPLY);
+ }
+
+ @Override
+ public void onSwitchChanged(Switch switchView, boolean isChecked) {
+ mMainSwitchPreference.setChecked(isChecked);
+ updateSelectorPreference(isChecked);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.FUELGAUGE_POWER_USAGE_MANAGE_BACKGROUND;
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ final Bundle bundle = getArguments();
+ final int uid = bundle.getInt(EXTRA_UID, 0);
+ final String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
+
+ controllers.add(new AllowBackgroundPreferenceController(context, uid, packageName));
+ controllers.add(new OptimizedPreferenceController(context, uid, packageName));
+ controllers.add(new UnrestrictedPreferenceController(context, uid, packageName));
+
+ return controllers;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.power_background_usage_detail;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @VisibleForTesting
+ void updateSelectorPreference(boolean isEnabled) {
+ mOptimizePreference.setEnabled(isEnabled);
+ mUnrestrictedPreference.setEnabled(isEnabled);
+ onRadioButtonClicked(isEnabled ? mOptimizePreference : null);
+ }
+
+ @VisibleForTesting
+ void notifyBackupManager() {
+ if (mOptimizationMode != mBatteryOptimizeUtils.getAppOptimizationMode()) {
+ final BackupManager backupManager = mBackupManager != null
+ ? mBackupManager : new BackupManager(getContext());
+ backupManager.dataChanged();
+ }
+ }
+
+ @VisibleForTesting
+ int getSelectedPreference() {
+ if (!mMainSwitchPreference.isChecked()) {
+ return BatteryOptimizeUtils.MODE_RESTRICTED;
+ } else if (mUnrestrictedPreference.isChecked()) {
+ return BatteryOptimizeUtils.MODE_UNRESTRICTED;
+ } else if (mOptimizePreference.isChecked()) {
+ return BatteryOptimizeUtils.MODE_OPTIMIZED;
+ } else {
+ return BatteryOptimizeUtils.MODE_UNKNOWN;
+ }
+ }
+
+ static void startPowerBackgroundUsageDetailPage(
+ Context context, Bundle args) {
+ new SubSettingLauncher(context)
+ .setDestination(PowerBackgroundUsageDetail.class.getName())
+ .setArguments(args)
+ .setSourceMetricsCategory(SettingsEnums.FUELGAUGE_POWER_USAGE_MANAGE_BACKGROUND)
+ .launch();
+ }
+
+ @VisibleForTesting
+ void initHeader() {
+ final View appSnippet = mHeaderPreference.findViewById(R.id.entity_header);
+ final Activity context = getActivity();
+ final Bundle bundle = getArguments();
+ EntityHeaderController controller = EntityHeaderController
+ .newInstance(context, this, appSnippet)
+ .setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
+ EntityHeaderController.ActionType.ACTION_NONE);
+
+ if (mAppEntry == null) {
+ controller.setLabel(bundle.getString(EXTRA_LABEL));
+
+ final int iconId = bundle.getInt(EXTRA_ICON_ID, 0);
+ if (iconId == 0) {
+ controller.setIcon(context.getPackageManager().getDefaultActivityIcon());
+ } else {
+ controller.setIcon(context.getDrawable(bundle.getInt(EXTRA_ICON_ID)));
+ }
+ } else {
+ mState.ensureIcon(mAppEntry);
+ controller.setLabel(mAppEntry);
+ controller.setIcon(mAppEntry);
+ controller.setIsInstantApp(AppUtils.isInstant(mAppEntry.info));
+ }
+
+ controller.done(true /* rebindActions */);
+ }
+
+ @VisibleForTesting
+ void initFooter() {
+ final String stateString;
+ final String footerString;
+ final Context context = getContext();
+
+ if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
+ // Present optimized only string when the package name is invalid.
+ stateString = context.getString(R.string.manager_battery_usage_optimized_only);
+ footerString = context.getString(
+ R.string.manager_battery_usage_footer_limited, stateString);
+ } else if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
+ // Present unrestricted only string when the package is system or default active app.
+ stateString = context.getString(R.string.manager_battery_usage_unrestricted_only);
+ footerString = context.getString(
+ R.string.manager_battery_usage_footer_limited, stateString);
+ } else {
+ // Present default string to normal app.
+ footerString = context.getString(R.string.manager_battery_usage_footer);
+ }
+ mFooterPreference.setTitle(footerString);
+ final Intent helpIntent = HelpUtils.getHelpIntent(context, context.getString(
+ R.string.help_url_app_usage_settings), /*backupContext=*/ "");
+ if (helpIntent != null) {
+ mFooterPreference.setLearnMoreAction(v ->
+ startActivityForResult(helpIntent, /*requestCode=*/ 0));
+ mFooterPreference.setLearnMoreText(
+ context.getString(R.string.manager_battery_usage_link_a11y));
+ }
+ }
+
+ private void onCreateBackgroundUsageState(String packageName) {
+ mOptimizePreference = findPreference(KEY_PREF_OPTIMIZED);
+ mUnrestrictedPreference = findPreference(KEY_PREF_UNRESTRICTED);
+ mMainSwitchPreference = findPreference(KEY_ALLOW_BACKGROUND_USAGE);
+ mFooterPreference = findPreference(KEY_FOOTER_PREFERENCE);
+
+ mOptimizePreference.setOnClickListener(this);
+ mUnrestrictedPreference.setOnClickListener(this);
+ mMainSwitchPreference.addOnSwitchChangeListener(this);
+
+ mBatteryOptimizeUtils = new BatteryOptimizeUtils(
+ getContext(), getArguments().getInt(EXTRA_UID), packageName);
+ }
+
+ private void updateSelectorPreferenceState(SelectorWithWidgetPreference preference,
+ String selectedKey) {
+ preference.setChecked(TextUtils.equals(selectedKey, preference.getKey()));
+ }
+
+ private void logMetricCategory(int currentOptimizeMode) {
+ if (currentOptimizeMode == mOptimizationMode) {
+ return;
+ }
+ int metricCategory = 0;
+ switch (currentOptimizeMode) {
+ case BatteryOptimizeUtils.MODE_UNRESTRICTED:
+ metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_UNRESTRICTED;
+ break;
+ case BatteryOptimizeUtils.MODE_OPTIMIZED:
+ metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_OPTIMIZED;
+ break;
+ case BatteryOptimizeUtils.MODE_RESTRICTED:
+ metricCategory = SettingsEnums.ACTION_APP_BATTERY_USAGE_RESTRICTED;
+ break;
+ }
+ if (metricCategory == 0) {
+ return;
+ }
+ int finalMetricCategory = metricCategory;
+ mExecutor.execute(() -> {
+ String packageName = BatteryUtils
+ .getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
+ FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
+ .action(
+ /* attribution */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
+ /* action */ finalMetricCategory,
+ /* pageId */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
+ packageName,
+ getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT));
+ });
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java b/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java
deleted file mode 100644
index 7db77f1..0000000
--- a/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-
-import com.android.settings.core.PreferenceControllerMixin;
-import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
-
-public class RestrictedPreferenceController extends AbstractPreferenceController
- implements PreferenceControllerMixin {
-
- private static final String TAG = "RESTRICTED_PREF";
-
- @VisibleForTesting String KEY_RESTRICTED_PREF = "restricted_pref";
- @VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
-
- public RestrictedPreferenceController(Context context, int uid, String packageName) {
- super(context);
- mBatteryOptimizeUtils = new BatteryOptimizeUtils(context, uid, packageName);
- }
-
- @Override
- public void updateState(Preference preference) {
-
- if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
- Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
- preference.setEnabled(false);
- return;
- } else {
- preference.setEnabled(true);
- }
-
- if (mBatteryOptimizeUtils.getAppOptimizationMode()
- == BatteryOptimizeUtils.MODE_RESTRICTED) {
- Log.d(TAG, "is restricted states");
- ((SelectorWithWidgetPreference) preference).setChecked(true);
- } else {
- ((SelectorWithWidgetPreference) preference).setChecked(false);
- if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
- Log.d(TAG, "is system or default app, disable pref");
- preference.setEnabled(false);
- }
- }
- }
-
- @Override
- public boolean isAvailable() {
- return true;
- }
-
- @Override
- public String getPreferenceKey() {
- return KEY_RESTRICTED_PREF;
- }
-
- @Override
- public boolean handlePreferenceTreeClick(Preference preference) {
- return getPreferenceKey().equals(preference.getKey());
- }
-}
diff --git a/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java b/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
index 4578723..b06b7e2 100644
--- a/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
@@ -17,7 +17,6 @@
package com.android.settings.fuelgauge;
import android.content.Context;
-import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -31,7 +30,9 @@
private static final String TAG = "UNRESTRICTED_PREF";
- @VisibleForTesting String KEY_UNRESTRICTED_PREF = "unrestricted_pref";
+ @VisibleForTesting
+ static final String KEY_UNRESTRICTED_PREF = "unrestricted_preference";
+
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
public UnrestrictedPreferenceController(Context context, int uid, String packageName) {
@@ -41,26 +42,11 @@
@Override
public void updateState(Preference preference) {
+ preference.setEnabled(mBatteryOptimizeUtils.isSelectorPreferenceEnabled());
- if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
- Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
- preference.setEnabled(false);
- return;
- } else {
- preference.setEnabled(true);
- }
-
- if (mBatteryOptimizeUtils.getAppOptimizationMode()
- == BatteryOptimizeUtils.MODE_UNRESTRICTED) {
- Log.d(TAG, "is unrestricted states");
- ((SelectorWithWidgetPreference) preference).setChecked(true);
- } else {
- ((SelectorWithWidgetPreference) preference).setChecked(false);
- if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
- Log.d(TAG, "is system or default app, disable pref");
- preference.setEnabled(false);
- }
- }
+ final boolean isUnrestricted = mBatteryOptimizeUtils.getAppOptimizationMode()
+ == BatteryOptimizeUtils.MODE_UNRESTRICTED;
+ ((SelectorWithWidgetPreference) preference).setChecked(isUnrestricted);
}
@Override
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index 9131051..80486cb 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -17,6 +17,7 @@
package com.android.settings.fuelgauge;
import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS;
+import static com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import static com.google.common.truth.Truth.assertThat;
@@ -53,13 +54,12 @@
import com.android.settings.testutils.shadow.ShadowActivityManager;
import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
-import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.LayoutPreference;
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.After;
import org.junit.Before;
@@ -95,9 +95,7 @@
private static final long FOREGROUND_SERVICE_TIME_MS = 444;
private static final long FOREGROUND_TIME_MS =
FOREGROUND_ACTIVITY_TIME_MS + FOREGROUND_SERVICE_TIME_MS;
- private static final String KEY_PREF_UNRESTRICTED = "unrestricted_pref";
- private static final String KEY_PREF_OPTIMIZED = "optimized_pref";
- private static final String KEY_PREF_RESTRICTED = "restricted_pref";
+ private static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private FragmentActivity mActivity;
@@ -127,10 +125,7 @@
private BackupManager mBackupManager;
private Context mContext;
- private FooterPreference mFooterPreference;
- private SelectorWithWidgetPreference mRestrictedPreference;
- private SelectorWithWidgetPreference mOptimizePreference;
- private SelectorWithWidgetPreference mUnrestrictedPreference;
+ private PrimarySwitchPreference mAllowBackgroundUsagePreference;
private AdvancedPowerUsageDetail mFragment;
private SettingsActivity mTestActivity;
private FakeFeatureFactory mFeatureFactory;
@@ -198,14 +193,9 @@
nullable(UserHandle.class));
doAnswer(callable).when(mActivity).startActivity(captor.capture());
- mFooterPreference = new FooterPreference(mContext);
- mRestrictedPreference = new SelectorWithWidgetPreference(mContext);
- mOptimizePreference = new SelectorWithWidgetPreference(mContext);
- mUnrestrictedPreference = new SelectorWithWidgetPreference(mContext);
- mFragment.mFooterPreference = mFooterPreference;
- mFragment.mRestrictedPreference = mRestrictedPreference;
- mFragment.mOptimizePreference = mOptimizePreference;
- mFragment.mUnrestrictedPreference = mUnrestrictedPreference;
+ mAllowBackgroundUsagePreference = new PrimarySwitchPreference(mContext);
+ mAllowBackgroundUsagePreference.setKey(KEY_ALLOW_BACKGROUND_USAGE);
+ mFragment.mAllowBackgroundUsagePreference = mAllowBackgroundUsagePreference;
}
@After
@@ -307,70 +297,60 @@
}
@Test
- public void initPreferenceForTriState_isValidPackageName_hasCorrectString() {
+ public void initFooter_isValidPackageName_hasCorrectString() {
when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
- mFragment.initPreferenceForTriState(mContext);
+ mFragment.initFooter();
- assertThat(mFooterPreference.getTitle().toString())
+ assertThat(mAllowBackgroundUsagePreference.getSummary().toString())
.isEqualTo("This app requires optimized battery usage.");
}
@Test
- public void initPreferenceForTriState_isSystemOrDefaultApp_hasCorrectString() {
+ public void initFooter_isSystemOrDefaultApp_hasCorrectString() {
when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- mFragment.initPreferenceForTriState(mContext);
+ mFragment.initFooter();
- assertThat(mFooterPreference.getTitle()
- .toString()).isEqualTo("This app requires unrestricted battery usage.");
+ assertThat(mAllowBackgroundUsagePreference.getSummary().toString())
+ .isEqualTo("This app requires unrestricted battery usage.");
}
@Test
- public void initPreferenceForTriState_hasCorrectString() {
+ public void initFooter_hasCorrectString() {
when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
- mFragment.initPreferenceForTriState(mContext);
+ mFragment.initFooter();
- assertThat(mFooterPreference.getTitle().toString())
- .isEqualTo("Changing how an app uses your battery can affect its performance.");
- }
-
- @Test
- public void onRadioButtonClicked_clickOptimizePref_optimizePreferenceChecked() {
- mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
- mRestrictedPreference.setKey(KEY_PREF_RESTRICTED);
- mUnrestrictedPreference.setKey(KEY_PREF_UNRESTRICTED);
- mFragment.onRadioButtonClicked(mOptimizePreference);
-
- assertThat(mOptimizePreference.isChecked()).isTrue();
- assertThat(mRestrictedPreference.isChecked()).isFalse();
- assertThat(mUnrestrictedPreference.isChecked()).isFalse();
+ assertThat(mAllowBackgroundUsagePreference.getSummary().toString())
+ .isEqualTo("Enable for real-time updates, disable to save battery");
}
@Test
public void onPause_optimizationModeChanged_logPreference()
throws PackageManager.NameNotFoundException, InterruptedException {
final String packageName = "testPackageName";
- final int mode = BatteryOptimizeUtils.MODE_RESTRICTED;
- mFragment.mOptimizationMode = mode;
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
+ final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+ final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+ mFragment.mOptimizationMode = restrictedMode;
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(restrictedMode);
when(mBatteryOptimizeUtils.getPackageName()).thenReturn(packageName);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn("com.android.vending");
- mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
- mFragment.onRadioButtonClicked(mOptimizePreference);
+ mFragment.onPreferenceChange(mAllowBackgroundUsagePreference, true);
+ verify(mBatteryOptimizeUtils).setAppUsageState(optimizedMode, Action.APPLY);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(optimizedMode);
mFragment.onPause();
TimeUnit.SECONDS.sleep(1);
verify(mMetricsFeatureProvider)
.action(
SettingsEnums.OPEN_APP_BATTERY_USAGE,
- SettingsEnums.ACTION_APP_BATTERY_USAGE_OPTIMIZED,
+ SettingsEnums.ACTION_APP_BATTERY_USAGE_ALLOW_BACKGROUND,
SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName,
/* consumed battery */ 0);
@@ -379,15 +359,20 @@
@Test
public void onPause_optimizationModeIsNotChanged_notInvokeLogging()
throws PackageManager.NameNotFoundException, InterruptedException {
- final int mode = BatteryOptimizeUtils.MODE_OPTIMIZED;
- mFragment.mOptimizationMode = mode;
- when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(mode);
+ final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+ final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+ mFragment.mOptimizationMode = restrictedMode;
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(restrictedMode);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(mInstallSourceInfo);
when(mInstallSourceInfo.getInitiatingPackageName()).thenReturn("com.android.vending");
- mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
- mFragment.onRadioButtonClicked(mOptimizePreference);
+ mFragment.onPreferenceChange(mAllowBackgroundUsagePreference, true);
+ verify(mBatteryOptimizeUtils).setAppUsageState(optimizedMode, Action.APPLY);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(optimizedMode);
+ mFragment.onPreferenceChange(mAllowBackgroundUsagePreference, false);
+ verify(mBatteryOptimizeUtils).setAppUsageState(restrictedMode, Action.APPLY);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(restrictedMode);
mFragment.onPause();
TimeUnit.SECONDS.sleep(1);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceControllerTest.java
new file mode 100644
index 0000000..be80e1e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AllowBackgroundPreferenceControllerTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2023 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import com.android.settingslib.widget.MainSwitchPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class AllowBackgroundPreferenceControllerTest {
+ private static final int UID = 12345;
+ private static final String PACKAGE_NAME = "com.android.app";
+
+ private AllowBackgroundPreferenceController mController;
+ private MainSwitchPreference mMainSwitchPreference;
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
+
+ @Mock private PackageManager mMockPackageManager;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ Context context = spy(RuntimeEnvironment.application);
+ BatteryUtils.getInstance(context).reset();
+ doReturn(UID)
+ .when(mMockPackageManager)
+ .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
+
+ mController = new AllowBackgroundPreferenceController(context, UID, PACKAGE_NAME);
+ mMainSwitchPreference = new MainSwitchPreference(RuntimeEnvironment.application);
+ mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(context, UID, PACKAGE_NAME));
+ mController.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
+ }
+
+ @Test
+ public void testUpdateState_isValidPackage_prefEnabled() {
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
+
+ mController.updateState(mMainSwitchPreference);
+
+ assertThat(mBatteryOptimizeUtils.isOptimizeModeMutable()).isTrue();
+ assertThat(mMainSwitchPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void testUpdateState_invalidPackage_prefDisabled() {
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
+
+ mController.updateState(mMainSwitchPreference);
+
+ assertThat(mBatteryOptimizeUtils.isOptimizeModeMutable()).isFalse();
+ assertThat(mMainSwitchPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void testUpdateState_isSystemOrDefaultAppAndRestrictedStates_prefChecked() {
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ BatteryOptimizeUtils.MODE_RESTRICTED);
+
+ mController.updateState(mMainSwitchPreference);
+
+ assertThat(mMainSwitchPreference.isEnabled()).isFalse();
+ assertThat(mMainSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ BatteryOptimizeUtils.MODE_OPTIMIZED);
+
+ mController.updateState(mMainSwitchPreference);
+
+ assertThat(mMainSwitchPreference.isEnabled()).isFalse();
+ assertThat(mMainSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void testUpdateState_isRestrictedStates_prefChecked() {
+ when(mBatteryOptimizeUtils.isOptimizeModeMutable()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ BatteryOptimizeUtils.MODE_RESTRICTED);
+
+ mController.updateState(mMainSwitchPreference);
+
+ assertThat(mMainSwitchPreference.isEnabled()).isTrue();
+ assertThat(mMainSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void testUpdateState_prefUnchecked() {
+ when(mBatteryOptimizeUtils.isOptimizeModeMutable()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ BatteryOptimizeUtils.MODE_OPTIMIZED);
+
+ mController.updateState(mMainSwitchPreference);
+
+ assertThat(mMainSwitchPreference.isEnabled()).isTrue();
+ assertThat(mMainSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void testHandlePreferenceTreeClick_samePrefKey_verifyAction() {
+ mMainSwitchPreference.setKey(
+ AllowBackgroundPreferenceController.KEY_ALLOW_BACKGROUND_USAGE);
+ mController.handlePreferenceTreeClick(mMainSwitchPreference);
+
+ assertThat(mController.handlePreferenceTreeClick(mMainSwitchPreference)).isTrue();
+ }
+
+ @Test
+ public void testHandlePreferenceTreeClick_incorrectPrefKey_noAction() {
+ assertThat(mController.handlePreferenceTreeClick(mMainSwitchPreference)).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
index b8c72ee..350d2ef 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -121,6 +121,7 @@
mContext = spy(RuntimeEnvironment.application);
mStringWriter = new StringWriter();
mPrintWriter = new PrintWriter(mStringWriter);
+ BatteryUtils.getInstance(mContext).reset();
doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
index e2058e7..bab19e5 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
@@ -31,10 +31,8 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.UserHandle;
-import android.os.UserManager;
import com.android.settings.TestUtils;
-import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry;
import com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleRadioButtonsController;
import org.junit.After;
@@ -75,6 +73,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ BatteryUtils.getInstance(mContext).reset();
doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mPackageManager).when(mContext).getPackageManager();
doReturn(UID).when(mPackageManager)
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
index 71bb998..bfed149 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
@@ -18,8 +18,13 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Before;
@@ -37,34 +42,41 @@
private OptimizedPreferenceController mController;
private SelectorWithWidgetPreference mPreference;
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
- @Mock BatteryOptimizeUtils mockBatteryOptimizeUtils;
+ @Mock PackageManager mMockPackageManager;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mController = new OptimizedPreferenceController(
- RuntimeEnvironment.application, UID, PACKAGE_NAME);
+ Context context = spy(RuntimeEnvironment.application);
+ BatteryUtils.getInstance(context).reset();
+ doReturn(UID)
+ .when(mMockPackageManager)
+ .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
+
+ mController = new OptimizedPreferenceController(context, UID, PACKAGE_NAME);
mPreference = new SelectorWithWidgetPreference(RuntimeEnvironment.application);
- mController.mBatteryOptimizeUtils = mockBatteryOptimizeUtils;
+ mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(context, UID, PACKAGE_NAME));
+ mController.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
}
@Test
public void testUpdateState_invalidPackage_prefEnabled() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
mController.updateState(mPreference);
- assertThat(mPreference.isEnabled()).isTrue();
+ assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void testUpdateState_isSystemOrDefaultAppAndOptimizeStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_OPTIMIZED);
mController.updateState(mPreference);
@@ -74,8 +86,8 @@
@Test
public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
mController.updateState(mPreference);
@@ -85,8 +97,8 @@
@Test
public void testUpdateState_isOptimizedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_OPTIMIZED);
mController.updateState(mPreference);
@@ -96,7 +108,7 @@
@Test
public void testUpdateState_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java
new file mode 100644
index 0000000..e6caf78
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerBackgroundUsageDetailTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2023 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;
+
+import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS;
+import static com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.AppOpsManager;
+import android.app.backup.BackupManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.widget.Switch;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.loader.app.LoaderManager;
+
+import com.android.settings.SettingsActivity;
+import com.android.settings.fuelgauge.batteryusage.BatteryEntry;
+import com.android.settings.testutils.shadow.ShadowActivityManager;
+import com.android.settings.testutils.shadow.ShadowEntityHeaderController;
+import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.applications.AppUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
+import com.android.settingslib.widget.FooterPreference;
+import com.android.settingslib.widget.LayoutPreference;
+import com.android.settingslib.widget.MainSwitchPreference;
+import com.android.settingslib.widget.SelectorWithWidgetPreference;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+ ShadowEntityHeaderController.class,
+ ShadowActivityManager.class,
+ com.android.settings.testutils.shadow.ShadowFragment.class,
+})
+public class PowerBackgroundUsageDetailTest {
+ private static final String APP_LABEL = "app label";
+ private static final String SUMMARY = "summary";
+ private static final int ICON_ID = 123;
+ private static final int UID = 1;
+ private static final String KEY_PREF_UNRESTRICTED = "unrestricted_preference";
+ private static final String KEY_PREF_OPTIMIZED = "optimized_preference";
+ private static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
+
+ private Context mContext;
+ private PowerBackgroundUsageDetail mFragment;
+ private FooterPreference mFooterPreference;
+ private MainSwitchPreference mMainSwitchPreference;
+ private SelectorWithWidgetPreference mOptimizePreference;
+ private SelectorWithWidgetPreference mUnrestrictedPreference;
+ private SettingsActivity mTestActivity;
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private FragmentActivity mActivity;
+ @Mock
+ private EntityHeaderController mEntityHeaderController;
+ @Mock
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
+ @Mock
+ private LayoutPreference mHeaderPreference;
+ @Mock
+ private ApplicationsState mState;
+ @Mock
+ private Bundle mBundle;
+ @Mock
+ private LoaderManager mLoaderManager;
+ @Mock
+ private ApplicationsState.AppEntry mAppEntry;
+ @Mock
+ private BatteryEntry mBatteryEntry;
+ @Mock
+ private BackupManager mBackupManager;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private AppOpsManager mAppOpsManager;
+ @Mock
+ private Switch mMockSwitch;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+ when(mContext.getPackageName()).thenReturn("foo");
+
+ mFragment = spy(new PowerBackgroundUsageDetail());
+ doReturn(mContext).when(mFragment).getContext();
+ doReturn(mActivity).when(mFragment).getActivity();
+ doReturn(SUMMARY).when(mFragment).getString(anyInt());
+ doReturn(APP_LABEL).when(mBundle).getString(nullable(String.class));
+ when(mFragment.getArguments()).thenReturn(mBundle);
+ doReturn(mLoaderManager).when(mFragment).getLoaderManager();
+
+ ShadowEntityHeaderController.setUseMock(mEntityHeaderController);
+ doReturn(mEntityHeaderController).when(mEntityHeaderController)
+ .setButtonActions(anyInt(), anyInt());
+ doReturn(mEntityHeaderController).when(mEntityHeaderController)
+ .setIcon(nullable(Drawable.class));
+ doReturn(mEntityHeaderController).when(mEntityHeaderController).setIcon(nullable(
+ ApplicationsState.AppEntry.class));
+ doReturn(mEntityHeaderController).when(mEntityHeaderController)
+ .setLabel(nullable(String.class));
+ doReturn(mEntityHeaderController).when(mEntityHeaderController)
+ .setLabel(nullable(String.class));
+ doReturn(mEntityHeaderController).when(mEntityHeaderController)
+ .setLabel(nullable(ApplicationsState.AppEntry.class));
+ doReturn(mEntityHeaderController).when(mEntityHeaderController)
+ .setSummary(nullable(String.class));
+
+ when(mBatteryEntry.getUid()).thenReturn(UID);
+ when(mBatteryEntry.getLabel()).thenReturn(APP_LABEL);
+ mBatteryEntry.mIconId = ICON_ID;
+
+ mFragment.mHeaderPreference = mHeaderPreference;
+ mFragment.mState = mState;
+ mFragment.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
+ mFragment.mBackupManager = mBackupManager;
+ mAppEntry.info = mock(ApplicationInfo.class);
+
+ mTestActivity = spy(new SettingsActivity());
+ doReturn(mPackageManager).when(mTestActivity).getPackageManager();
+ doReturn(mPackageManager).when(mActivity).getPackageManager();
+ doReturn(mAppOpsManager).when(mTestActivity).getSystemService(Context.APP_OPS_SERVICE);
+
+ final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
+
+ Answer<Void> callable = invocation -> {
+ mBundle = captor.getValue().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);
+ System.out.println("mBundle = " + mBundle);
+ return null;
+ };
+ doAnswer(callable).when(mActivity).startActivityAsUser(captor.capture(),
+ nullable(UserHandle.class));
+ doAnswer(callable).when(mActivity).startActivity(captor.capture());
+
+ mFooterPreference = spy(new FooterPreference(mContext));
+ mMainSwitchPreference = spy(new MainSwitchPreference(mContext));
+ mMainSwitchPreference.setKey(KEY_ALLOW_BACKGROUND_USAGE);
+ mOptimizePreference = spy(new SelectorWithWidgetPreference(mContext));
+ mOptimizePreference.setKey(KEY_PREF_OPTIMIZED);
+ mUnrestrictedPreference = spy(new SelectorWithWidgetPreference(mContext));
+ mUnrestrictedPreference.setKey(KEY_PREF_UNRESTRICTED);
+ mFragment.mFooterPreference = mFooterPreference;
+ mFragment.mMainSwitchPreference = mMainSwitchPreference;
+ mFragment.mOptimizePreference = mOptimizePreference;
+ mFragment.mUnrestrictedPreference = mUnrestrictedPreference;
+ }
+
+ @After
+ public void reset() {
+ ShadowEntityHeaderController.reset();
+ }
+
+ @Test
+ public void initHeader_NoAppEntry_BuildByBundle() {
+ mFragment.mAppEntry = null;
+ mFragment.initHeader();
+
+ verify(mEntityHeaderController).setIcon(nullable(Drawable.class));
+ verify(mEntityHeaderController).setLabel(APP_LABEL);
+ }
+
+ @Test
+ public void initHeader_HasAppEntry_BuildByAppEntry() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ new InstantAppDataProvider() {
+ @Override
+ public boolean isInstantApp(ApplicationInfo info) {
+ return false;
+ }
+ });
+ mFragment.mAppEntry = mAppEntry;
+ mFragment.initHeader();
+
+ verify(mEntityHeaderController).setIcon(mAppEntry);
+ verify(mEntityHeaderController).setLabel(mAppEntry);
+ verify(mEntityHeaderController).setIsInstantApp(false);
+ }
+
+ @Test
+ public void initHeader_HasAppEntry_InstantApp() {
+ ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
+ new InstantAppDataProvider() {
+ @Override
+ public boolean isInstantApp(ApplicationInfo info) {
+ return true;
+ }
+ });
+ mFragment.mAppEntry = mAppEntry;
+ mFragment.initHeader();
+
+ verify(mEntityHeaderController).setIcon(mAppEntry);
+ verify(mEntityHeaderController).setLabel(mAppEntry);
+ verify(mEntityHeaderController).setIsInstantApp(true);
+ }
+
+ @Test
+ public void initFooter_hasCorrectString() {
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
+
+ mFragment.initFooter();
+
+ assertThat(mFooterPreference.getTitle().toString())
+ .isEqualTo("Changing how an app uses your battery can affect its performance.");
+ }
+
+ @Test
+ public void onSwitchChanged_fromUnrestrictedModeSetDisabled_becomeRestrictedMode() {
+ final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+ final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+ mFragment.mOptimizationMode = optimizedMode;
+
+ mFragment.onSwitchChanged(mMockSwitch, /*isChecked=*/ false);
+
+ verify(mOptimizePreference).setEnabled(false);
+ verify(mUnrestrictedPreference).setEnabled(false);
+ verify(mFragment).onRadioButtonClicked(null);
+ verify(mMainSwitchPreference).setChecked(false);
+ assertThat(mFragment.getSelectedPreference()).isEqualTo(restrictedMode);
+ verify(mBatteryOptimizeUtils).setAppUsageState(restrictedMode, Action.APPLY);
+ }
+
+ @Test
+ public void onSwitchChanged_fromRestrictedModeSetEnabled_becomeOptimizedMode() {
+ final int restrictedMode = BatteryOptimizeUtils.MODE_RESTRICTED;
+ final int optimizedMode = BatteryOptimizeUtils.MODE_OPTIMIZED;
+ mFragment.mOptimizationMode = restrictedMode;
+
+ mFragment.onSwitchChanged(mMockSwitch, /*isChecked=*/ true);
+
+ verify(mOptimizePreference).setEnabled(true);
+ verify(mUnrestrictedPreference).setEnabled(true);
+ verify(mFragment).onRadioButtonClicked(mOptimizePreference);
+ verify(mMainSwitchPreference).setChecked(true);
+ verify(mOptimizePreference).setChecked(true);
+ assertThat(mFragment.getSelectedPreference()).isEqualTo(optimizedMode);
+ verify(mBatteryOptimizeUtils).setAppUsageState(optimizedMode, Action.APPLY);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java
deleted file mode 100644
index bcddbc2..0000000
--- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.fuelgauge;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import com.android.settingslib.widget.SelectorWithWidgetPreference;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class RestrictedPreferenceControllerTest {
- private static final int UID = 12345;
- private static final String PACKAGE_NAME = "com.android.app";
-
- private RestrictedPreferenceController mController;
- private SelectorWithWidgetPreference mPreference;
-
- @Mock BatteryOptimizeUtils mockBatteryOptimizeUtils;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- mController = new RestrictedPreferenceController(
- RuntimeEnvironment.application, UID, PACKAGE_NAME);
- mPreference = new SelectorWithWidgetPreference(RuntimeEnvironment.application);
- mController.mBatteryOptimizeUtils = mockBatteryOptimizeUtils;
- }
-
- @Test
- public void testUpdateState_isValidPackage_prefEnabled() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isTrue();
- }
-
- @Test
- public void testUpdateState_invalidPackage_prefDisabled() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isFalse();
- }
-
- @Test
- public void testUpdateState_isSystemOrDefaultAppAndRestrictedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
- BatteryOptimizeUtils.MODE_RESTRICTED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isFalse();
- assertThat(mPreference.isEnabled()).isFalse();
- }
-
- @Test
- public void testUpdateState_isRestrictedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
- BatteryOptimizeUtils.MODE_RESTRICTED);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void testUpdateState_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void testHandlePreferenceTreeClick_samePrefKey_verifyAction() {
- mPreference.setKey(mController.KEY_RESTRICTED_PREF);
- mController.handlePreferenceTreeClick(mPreference);
-
- assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue();
- }
-
- @Test
- public void testHandlePreferenceTreeClick_incorrectPrefKey_noAction() {
- assertThat(mController.handlePreferenceTreeClick(mPreference)).isFalse();
- }
-}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
index 9bed9ba..5489196 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
@@ -18,8 +18,13 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Before;
@@ -37,42 +42,53 @@
private UnrestrictedPreferenceController mController;
private SelectorWithWidgetPreference mPreference;
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
- @Mock BatteryOptimizeUtils mockBatteryOptimizeUtils;
+ @Mock PackageManager mMockPackageManager;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mController = new UnrestrictedPreferenceController(
- RuntimeEnvironment.application, UID, PACKAGE_NAME);
+ Context context = spy(RuntimeEnvironment.application);
+ BatteryUtils.getInstance(context).reset();
+ doReturn(UID)
+ .when(mMockPackageManager)
+ .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
+
+ mController = new UnrestrictedPreferenceController(context, UID, PACKAGE_NAME);
mPreference = new SelectorWithWidgetPreference(RuntimeEnvironment.application);
- mController.mBatteryOptimizeUtils = mockBatteryOptimizeUtils;
+ mBatteryOptimizeUtils = spy(new BatteryOptimizeUtils(context, UID, PACKAGE_NAME));
+ mController.mBatteryOptimizeUtils = mBatteryOptimizeUtils;
}
@Test
public void testUpdateState_isValidPackage_prefEnabled() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
mController.updateState(mPreference);
+ assertThat(mBatteryOptimizeUtils.isOptimizeModeMutable()).isTrue();
assertThat(mPreference.isEnabled()).isTrue();
}
@Test
public void testUpdateState_invalidPackage_prefDisabled() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
mController.updateState(mPreference);
+ assertThat(mBatteryOptimizeUtils.isOptimizeModeMutable()).isFalse();
assertThat(mPreference.isEnabled()).isFalse();
}
@Test
public void testUpdateState_isSystemOrDefaultAppAndUnrestrictedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
- when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_UNRESTRICTED);
mController.updateState(mPreference);
@@ -82,32 +98,38 @@
@Test
public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ BatteryOptimizeUtils.MODE_OPTIMIZED);
mController.updateState(mPreference);
- assertThat(mPreference.isChecked()).isFalse();
assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void testUpdateState_isUnrestrictedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
- when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ when(mBatteryOptimizeUtils.isOptimizeModeMutable()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_UNRESTRICTED);
mController.updateState(mPreference);
+ assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void testUpdateState_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isOptimizeModeMutable()).thenReturn(true);
+ when(mBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
+ BatteryOptimizeUtils.MODE_OPTIMIZED);
mController.updateState(mPreference);
+ assertThat(mPreference.isEnabled()).isTrue();
assertThat(mPreference.isChecked()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index ae726b7..f43feec 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -82,6 +82,7 @@
MockitoAnnotations.initMocks(this);
ShadowUserHandle.reset();
mContext = spy(RuntimeEnvironment.application);
+ BatteryUtils.getInstance(mContext).reset();
doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mMockUserManager).when(mContext).getSystemService(UserManager.class);
doReturn(mMockPackageManager).when(mContext).getPackageManager();
@@ -461,9 +462,6 @@
@Test
public void testIsUninstalledEntry_uninstalledApp_returnTrue() throws Exception {
- doReturn(BatteryUtils.UID_NULL)
- .when(mMockPackageManager)
- .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
final ContentValues values =
getContentValuesWithType(ConvertUtils.CONSUMER_TYPE_UID_BATTERY);
values.put(BatteryHistEntry.KEY_UID, UNINSTALLED_UID);