Bug: 360260798 Test: manual Flag: EXEMPT bug fix Change-Id: I77bf9a7be75257be7871714afaf1fba81787f8b1
332 lines
14 KiB
Java
332 lines
14 KiB
Java
/*
|
|
* 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.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.CompoundButton;
|
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
|
|
|
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.fuelgauge.batteryusage.AppOptModeSharedPreferencesUtils;
|
|
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.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, OnCheckedChangeListener {
|
|
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 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();
|
|
mLogStringBuilder = new StringBuilder("onResume mode = ").append(mOptimizationMode);
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
super.onPause();
|
|
|
|
final int currentOptimizeMode = mBatteryOptimizeUtils.getAppOptimizationMode();
|
|
final Context applicationContext = requireContext().getApplicationContext();
|
|
mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
|
|
logMetricCategory(currentOptimizeMode);
|
|
mExecutor.execute(
|
|
() -> {
|
|
if (currentOptimizeMode != mOptimizationMode) {
|
|
AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(
|
|
applicationContext, mBatteryOptimizeUtils.getUid());
|
|
}
|
|
BatteryOptimizeLogUtils.writeLog(
|
|
applicationContext,
|
|
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 onCheckedChanged(CompoundButton buttonView, 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
|
|
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
|
|
.LEAVE_POWER_USAGE_MANAGE_BACKGROUND,
|
|
/* action */ finalMetricCategory,
|
|
/* pageId */ SettingsEnums
|
|
.FUELGAUGE_POWER_USAGE_MANAGE_BACKGROUND,
|
|
packageName,
|
|
getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT));
|
|
});
|
|
}
|
|
}
|