Merge "Refactor background optimization mode in Power Usage Detail page." into main
This commit is contained in:
@@ -27,10 +27,13 @@ import android.content.Intent;
|
||||
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.BatteryDiffEntry;
|
||||
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 @@ import java.util.concurrent.Executors;
|
||||
*/
|
||||
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 class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
@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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
@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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
|
||||
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 class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
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));
|
||||
detailInfoString =
|
||||
context.getString(
|
||||
R.string.manager_battery_usage_allow_background_usage_summary);
|
||||
}
|
||||
mAllowBackgroundUsagePreference.setSummary(detailInfoString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -412,9 +395,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
}
|
||||
|
||||
@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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
}
|
||||
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 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
* 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.
|
||||
@@ -17,50 +17,45 @@
|
||||
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.PrimarySwitchPreference;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.widget.SelectorWithWidgetPreference;
|
||||
import com.android.settingslib.widget.MainSwitchPreference;
|
||||
|
||||
public class RestrictedPreferenceController extends AbstractPreferenceController
|
||||
/** Controller to update the app background usage state */
|
||||
public class AllowBackgroundPreferenceController extends AbstractPreferenceController
|
||||
implements PreferenceControllerMixin {
|
||||
|
||||
private static final String TAG = "RESTRICTED_PREF";
|
||||
private static final String TAG = "AllowBackgroundPreferenceController";
|
||||
|
||||
@VisibleForTesting static final String KEY_ALLOW_BACKGROUND_USAGE = "allow_background_usage";
|
||||
|
||||
@VisibleForTesting String KEY_RESTRICTED_PREF = "restricted_pref";
|
||||
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
|
||||
|
||||
public RestrictedPreferenceController(Context context, int uid, String packageName) {
|
||||
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());
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
final boolean isAllowBackground = mBatteryOptimizeUtils.getAppOptimizationMode()
|
||||
!= BatteryOptimizeUtils.MODE_RESTRICTED;
|
||||
setChecked(preference, isAllowBackground);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,7 +65,7 @@ public class RestrictedPreferenceController extends AbstractPreferenceController
|
||||
|
||||
@Override
|
||||
public String getPreferenceKey() {
|
||||
return KEY_RESTRICTED_PREF;
|
||||
return KEY_ALLOW_BACKGROUND_USAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,6 +146,22 @@ public class BatteryOptimizeUtils {
|
||||
return isSystemOrDefaultApp(mContext, mPowerAllowListBackend, mPackageName, mUid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -88,6 +88,7 @@ public class BatteryUtils {
|
||||
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 @@ public class BatteryUtils {
|
||||
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 @@ public class BatteryUtils {
|
||||
&& 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);
|
||||
|
||||
@@ -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 @@ public class OptimizedPreferenceController extends AbstractPreferenceController
|
||||
|
||||
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 @@ public class OptimizedPreferenceController extends AbstractPreferenceController
|
||||
|
||||
@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
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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 @@ public class UnrestrictedPreferenceController extends AbstractPreferenceControll
|
||||
|
||||
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 @@ public class UnrestrictedPreferenceController extends AbstractPreferenceControll
|
||||
|
||||
@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
|
||||
|
||||
Reference in New Issue
Block a user