Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81e02893 authored by mxyyiyi's avatar mxyyiyi
Browse files

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
parent 5ac8a4e2
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -5430,6 +5430,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] -->
+50 −0
Original line number Diff line number Diff line
<?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
+4 −23
Original line number Diff line number Diff line
@@ -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
+70 −96
Original line number Diff line number Diff line
@@ -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;
@@ -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);
    }
}
+22 −27
Original line number Diff line number Diff line
/*
 * 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
Loading