Refactor background optimization mode in Power Usage Detail page.
[Screenshot]: before: https://screenshot.googleplex.com/6m5jYWHofY2pFov after: [App battery usage] - [normal] https://screenshot.googleplex.com/7aurWk7cHKaWds7 - [always unrestried/optimized] https://screenshot.googleplex.com/3rGAh4ccUYTKBAr [Allow Background usage] - [Restricted]: https://screenshot.googleplex.com/MPXjQe5kPWw2nhr - [Optimized]: https://screenshot.googleplex.com/6w4zTT6r34APnGc - [Unrestricted]: https://screenshot.googleplex.com/97FgvHWMrwASqYH Bug: 302063050 Bug: 306295660 Bug: 308359833 Test: manual Change-Id: I3237d015549fe26e62d6d68c13403cc2cbdf0017
This commit is contained in:
@@ -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));
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user