Merge changes Iced0fa59,Ic354ac91,I0b4cb6ca,I9c1d3761 into sc-dev am: e3cf049039

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/14209651

Change-Id: I742dc967380c74f7c09b3346077217a9f9c49212
This commit is contained in:
Wesley Wang
2021-04-19 10:32:00 +00:00
committed by Automerger Merge Worker
11 changed files with 1041 additions and 1 deletions

View File

@@ -25,6 +25,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.UserHandle;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@@ -48,6 +49,7 @@ import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.utils.StringUtil;
import com.android.settingslib.widget.LayoutPreference;
import com.android.settingslib.widget.RadioButtonPreference;
import java.util.ArrayList;
import java.util.List;
@@ -60,7 +62,7 @@ import java.util.List;
*/
public class AdvancedPowerUsageDetail extends DashboardFragment implements
ButtonActionDialogFragment.AppButtonsDialogListener,
BatteryTipPreferenceController.BatteryTipListener {
BatteryTipPreferenceController.BatteryTipListener, RadioButtonPreference.OnClickListener {
public static final String TAG = "AdvancedPowerDetail";
public static final String EXTRA_UID = "extra_uid";
@@ -75,6 +77,10 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
private static final String KEY_PREF_FOREGROUND = "app_usage_foreground";
private static final String KEY_PREF_BACKGROUND = "app_usage_background";
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 int REQUEST_UNINSTALL = 0;
private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
@@ -87,13 +93,26 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
ApplicationsState.AppEntry mAppEntry;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting
BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting
Preference mForegroundPreference;
@VisibleForTesting
Preference mBackgroundPreference;
@VisibleForTesting
Preference mFooterPreference;
@VisibleForTesting
RadioButtonPreference mRestrictedPreference;
@VisibleForTesting
RadioButtonPreference mOptimizePreference;
@VisibleForTesting
RadioButtonPreference mUnrestrictedPreference;
private AppButtonsPreferenceController mAppButtonsPreferenceController;
private BackgroundActivityPreferenceController mBackgroundActivityPreferenceController;
private UnrestrictedPreferenceController mUnrestrictedPreferenceController;
private OptimizedPreferenceController mOptimizedPreferenceController;
private RestrictedPreferenceController mRestrictedPreferenceController;
private String mPackageName;
@@ -174,8 +193,19 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
mPackageName = getArguments().getString(EXTRA_PACKAGE_NAME);
mForegroundPreference = findPreference(KEY_PREF_FOREGROUND);
mBackgroundPreference = findPreference(KEY_PREF_BACKGROUND);
mFooterPreference = findPreference(KEY_FOOTER_PREFERENCE);
mHeaderPreference = (LayoutPreference) findPreference(KEY_PREF_HEADER);
mUnrestrictedPreference = findPreference(KEY_PREF_UNRESTRICTED);
mOptimizePreference = findPreference(KEY_PREF_OPTIMIZED);
mRestrictedPreference = findPreference(KEY_PREF_RESTRICTED);
mUnrestrictedPreference.setOnClickListener(this);
mOptimizePreference.setOnClickListener(this);
mRestrictedPreference.setOnClickListener(this);
mBatteryOptimizeUtils = new BatteryOptimizeUtils(
getContext(), getArguments().getInt(EXTRA_UID), mPackageName);
if (mPackageName != null) {
mAppEntry = mState.getEntry(mPackageName, UserHandle.myUserId());
}
@@ -241,6 +271,26 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
backgroundTimeMs,
/* withSeconds */ false,
/* collapseTimeUnit */ false)));
final String stateString;
final String footerString;
//TODO(b/178197718) Update strings
if (!mBatteryOptimizeUtils.isValidPackageName()) {
//Present optimized only string when the package name is invalid.
stateString = context.getString(R.string.manager_battery_usage_optimized_title);
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_title);
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(Html.fromHtml(footerString, Html.FROM_HTML_MODE_COMPACT));
}
@Override
@@ -274,6 +324,15 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
(SettingsActivity) getActivity(), this, getSettingsLifecycle(), packageName, mState,
REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN);
controllers.add(mAppButtonsPreferenceController);
mUnrestrictedPreferenceController =
new UnrestrictedPreferenceController(context, uid, packageName);
mOptimizedPreferenceController =
new OptimizedPreferenceController(context, uid, packageName);
mRestrictedPreferenceController =
new RestrictedPreferenceController(context, uid, packageName);
controllers.add(mUnrestrictedPreferenceController);
controllers.add(mOptimizedPreferenceController);
controllers.add(mRestrictedPreferenceController);
return controllers;
}
@@ -298,4 +357,15 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
mBackgroundActivityPreferenceController.updateSummary(
findPreference(mBackgroundActivityPreferenceController.getPreferenceKey()));
}
@Override
public void onRadioButtonClicked(RadioButtonPreference selected) {
updatePreferenceState(mUnrestrictedPreference, selected.getKey());
updatePreferenceState(mOptimizePreference, selected.getKey());
updatePreferenceState(mRestrictedPreference, selected.getKey());
}
private void updatePreferenceState(RadioButtonPreference preference, String selectedKey) {
preference.setChecked(selectedKey.equals(preference.getKey()));
}
}

View File

@@ -0,0 +1,121 @@
/*
* 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.app.AppOpsManager;
import android.content.Context;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
/** A utility class for application usage operation. */
public class BatteryOptimizeUtils {
private static final String TAG = "BatteryOptimizeUtils";
@VisibleForTesting AppOpsManager mAppOpsManager;
@VisibleForTesting BatteryUtils mBatteryUtils;
@VisibleForTesting PowerAllowlistBackend mPowerAllowListBackend;
private final String mPackageName;
private final int mUid;
private int mMode;
private boolean mAllowListed;
/**
* Usage type of application.
*/
public enum AppUsageState {
UNKNOWN,
RESTRICTED,
UNRESTRICTED,
OPTIMIZED,
}
public BatteryOptimizeUtils(Context context, int uid, String packageName) {
mUid = uid;
mPackageName = packageName;
mAppOpsManager = context.getSystemService(AppOpsManager.class);
mBatteryUtils = BatteryUtils.getInstance(context);
mPowerAllowListBackend = PowerAllowlistBackend.getInstance(context);
mMode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName);
mAllowListed = mPowerAllowListBackend.isAllowlisted(mPackageName);
}
public AppUsageState getAppUsageState() {
refreshState();
if (!mAllowListed && mMode == AppOpsManager.MODE_IGNORED) {
return AppUsageState.RESTRICTED;
} else if (mAllowListed && mMode == AppOpsManager.MODE_ALLOWED) {
return AppUsageState.UNRESTRICTED;
} else if (!mAllowListed && mMode == AppOpsManager.MODE_ALLOWED) {
return AppUsageState.OPTIMIZED;
} else {
Log.d(TAG, "get unknown app usage state.");
return AppUsageState.UNKNOWN;
}
}
public void setAppUsageState(AppUsageState state) {
switch (state) {
case RESTRICTED:
mBatteryUtils.setForceAppStandby(mUid, mPackageName, AppOpsManager.MODE_IGNORED);
mPowerAllowListBackend.removeApp(mPackageName);
break;
case UNRESTRICTED:
mBatteryUtils.setForceAppStandby(mUid, mPackageName, AppOpsManager.MODE_ALLOWED);
mPowerAllowListBackend.addApp(mPackageName);
break;
case OPTIMIZED:
mBatteryUtils.setForceAppStandby(mUid, mPackageName, AppOpsManager.MODE_ALLOWED);
mPowerAllowListBackend.removeApp(mPackageName);
break;
default:
Log.d(TAG, "set unknown app usage state.");
}
}
/**
* Return {@code true} if package name is valid (can get an uid).
*/
public boolean isValidPackageName() {
return mBatteryUtils.getPackageUid(mPackageName) != BatteryUtils.UID_NULL;
}
/**
* Return {@code true} if this package is system or default active app.
*/
public boolean isSystemOrDefaultApp() {
mPowerAllowListBackend.refreshList();
return mPowerAllowListBackend.isSysAllowlisted(mPackageName)
|| mPowerAllowListBackend.isDefaultActiveApp(mPackageName);
}
private void refreshState() {
mPowerAllowListBackend.refreshList();
mAllowListed = mPowerAllowListBackend.isAllowlisted(mPackageName);
mMode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName);
Log.d(TAG, String.format("refresh %s state, allowlisted = %s, mode = %d",
mPackageName,
mAllowListed,
mMode));
}
}

View File

@@ -0,0 +1,85 @@
/*
* 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.android.settings.fuelgauge.BatteryOptimizeUtils.AppUsageState.OPTIMIZED;
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.RadioButtonPreference;
public class OptimizedPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin {
private static final String TAG = "OPTIMIZED_PREF";
@VisibleForTesting String KEY_OPTIMIZED_PREF = "optimized_pref";
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
public OptimizedPreferenceController(Context context, int uid, String packageName) {
super(context);
mBatteryOptimizeUtils = new BatteryOptimizeUtils(context, uid, packageName);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public void updateState(Preference preference) {
if (!mBatteryOptimizeUtils.isValidPackageName()) {
Log.d(TAG, "invalid package name, optimized states only");
preference.setEnabled(true);
((RadioButtonPreference) preference).setChecked(true);
return;
}
if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
Log.d(TAG, "is system or default app, disable pref");
((RadioButtonPreference) preference).setChecked(false);
preference.setEnabled(false);
} else if (mBatteryOptimizeUtils.getAppUsageState() == OPTIMIZED) {
Log.d(TAG, "is optimized states");
((RadioButtonPreference) preference).setChecked(true);
} else {
((RadioButtonPreference) preference).setChecked(false);
}
}
@Override
public String getPreferenceKey() {
return KEY_OPTIMIZED_PREF;
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (!KEY_OPTIMIZED_PREF.equals(preference.getKey())) {
return false;
}
mBatteryOptimizeUtils.setAppUsageState(OPTIMIZED);
Log.d(TAG, "Set optimized");
return true;
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.android.settings.fuelgauge.BatteryOptimizeUtils.AppUsageState.RESTRICTED;
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.RadioButtonPreference;
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.isValidPackageName()) {
Log.d(TAG, "invalid package name, disable pref");
preference.setEnabled(false);
return;
} else {
preference.setEnabled(true);
}
if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
Log.d(TAG, "is system or default app, disable pref");
((RadioButtonPreference) preference).setChecked(false);
preference.setEnabled(false);
} else if (mBatteryOptimizeUtils.getAppUsageState() == RESTRICTED) {
Log.d(TAG, "is restricted states");
((RadioButtonPreference) preference).setChecked(true);
} else {
((RadioButtonPreference) preference).setChecked(false);
}
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return KEY_RESTRICTED_PREF;
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (!KEY_RESTRICTED_PREF.equals(preference.getKey())) {
return false;
}
mBatteryOptimizeUtils.setAppUsageState(RESTRICTED);
Log.d(TAG, "Set restricted");
return true;
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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.android.settings.fuelgauge.BatteryOptimizeUtils.AppUsageState.UNRESTRICTED;
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.RadioButtonPreference;
public class UnrestrictedPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin {
private static final String TAG = "UNRESTRICTED_PREF";
@VisibleForTesting String KEY_UNRESTRICTED_PREF = "unrestricted_pref";
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
public UnrestrictedPreferenceController(Context context, int uid, String packageName) {
super(context);
mBatteryOptimizeUtils = new BatteryOptimizeUtils(context, uid, packageName);
}
@Override
public void updateState(Preference preference) {
if (!mBatteryOptimizeUtils.isValidPackageName()) {
Log.d(TAG, "invalid package name, disable pref");
preference.setEnabled(false);
return;
} else {
preference.setEnabled(true);
}
if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
Log.d(TAG, "is system or default app, unrestricted states only");
((RadioButtonPreference) preference).setChecked(true);
} else if (mBatteryOptimizeUtils.getAppUsageState() == UNRESTRICTED) {
Log.d(TAG, "is unrestricted states");
((RadioButtonPreference) preference).setChecked(true);
} else {
((RadioButtonPreference) preference).setChecked(false);
}
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return KEY_UNRESTRICTED_PREF;
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (!KEY_UNRESTRICTED_PREF.equals(preference.getKey())) {
return false;
}
mBatteryOptimizeUtils.setAppUsageState(UNRESTRICTED);
Log.d(TAG, "Set unrestricted");
return true;
}
}