diff --git a/res/values/strings.xml b/res/values/strings.xml index 32ab1ccbeed..4a6b0d04a1a 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4932,6 +4932,16 @@ Prevent apps from using extra battery in the background + + On / Restricting apps automatically + + Off + + + %1$d app restricted + %1$d apps restricted + + Stop app? diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml index ac96151557e..e57be2600f9 100644 --- a/res/xml/power_usage_summary.xml +++ b/res/xml/power_usage_summary.xml @@ -42,7 +42,8 @@ + android:title="@string/smart_battery_manager_title" + settings:controller="com.android.settings.fuelgauge.batterytip.BatteryManagerPreferenceController"/> packageOpsList = mAppOpsManager.getPackagesForOps( - new int[]{AppOpsManager.OP_RUN_ANY_IN_BACKGROUND}); - mAppInfos = new ArrayList<>(); - - for (int i = 0, size = CollectionUtils.size(packageOpsList); i < size; i++) { - final AppOpsManager.PackageOps packageOps = packageOpsList.get(i); - final List entries = packageOps.getOps(); - for (int j = 0; j < entries.size(); j++) { - AppOpsManager.OpEntry ent = entries.get(j); - if (ent.getOp() != AppOpsManager.OP_RUN_ANY_IN_BACKGROUND) { - continue; - } - if (ent.getMode() != AppOpsManager.MODE_ALLOWED) { - mAppInfos.add(new AppInfo.Builder() - .setPackageName(packageOps.getPackageName()) - .setUid(packageOps.getUid()) - .build()); - } - } - } + mAppInfos = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager); final int num = mAppInfos.size(); // Enable the preference if some apps already been restricted, otherwise disable it diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java new file mode 100644 index 00000000000..087f98317eb --- /dev/null +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceController.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 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.batterytip; + +import android.app.AppOpsManager; +import android.content.Context; +import android.provider.Settings; +import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.Preference; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.fuelgauge.PowerUsageFeatureProvider; +import com.android.settings.overlay.FeatureFactory; + +/** + * Preference controller to control the battery manager + */ +public class BatteryManagerPreferenceController extends BasePreferenceController { + private static final String KEY_BATTERY_MANAGER = "smart_battery_manager"; + private static final int ON = 1; + private PowerUsageFeatureProvider mPowerUsageFeatureProvider; + private AppOpsManager mAppOpsManager; + + public BatteryManagerPreferenceController(Context context) { + super(context, KEY_BATTERY_MANAGER); + mPowerUsageFeatureProvider = FeatureFactory.getFactory( + context).getPowerUsageFeatureProvider(context); + mAppOpsManager = context.getSystemService(AppOpsManager.class); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + final int num = BatteryTipUtils.getRestrictedAppsList(mAppOpsManager).size(); + final String setting = mPowerUsageFeatureProvider.isSmartBatterySupported() + ? Settings.Global.APP_STANDBY_ENABLED + : Settings.Global.APP_AUTO_RESTRICTION_ENABLED; + final boolean featureOn = + Settings.Global.getInt(mContext.getContentResolver(), setting, ON) == ON; + + updateSummary(preference, featureOn, num); + } + + @VisibleForTesting + void updateSummary(Preference preference, boolean featureOn, int num) { + if (num > 0) { + preference.setSummary(mContext.getResources().getQuantityString( + R.plurals.battery_manager_app_restricted, num, num)); + } else if (featureOn) { + preference.setSummary(R.string.battery_manager_on); + } else { + preference.setSummary(R.string.battery_manager_off); + } + } +} diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java index e9e30dec5cc..a2179892dbb 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java @@ -16,11 +16,14 @@ package com.android.settings.fuelgauge.batterytip; +import android.app.AppOpsManager; import android.app.PendingIntent; import android.app.StatsManager; import android.content.Context; import android.content.Intent; +import android.support.annotation.NonNull; +import com.android.internal.util.CollectionUtils; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.fuelgauge.batterytip.actions.BatterySaverAction; @@ -33,12 +36,44 @@ import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip; import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip; +import java.util.ArrayList; +import java.util.List; + /** * Utility class for {@link BatteryTip} */ public class BatteryTipUtils { private static final int REQUEST_CODE = 0; + /** + * Get a list of restricted apps with {@link AppOpsManager#OP_RUN_ANY_IN_BACKGROUND} + */ + @NonNull + public static List getRestrictedAppsList(AppOpsManager appOpsManager) { + final List packageOpsList = appOpsManager.getPackagesForOps( + new int[]{AppOpsManager.OP_RUN_ANY_IN_BACKGROUND}); + final List appInfos = new ArrayList<>(); + + for (int i = 0, size = CollectionUtils.size(packageOpsList); i < size; i++) { + final AppOpsManager.PackageOps packageOps = packageOpsList.get(i); + final List entries = packageOps.getOps(); + for (int j = 0, entriesSize = entries.size(); j < entriesSize; j++) { + AppOpsManager.OpEntry entry = entries.get(j); + if (entry.getOp() != AppOpsManager.OP_RUN_ANY_IN_BACKGROUND) { + continue; + } + if (entry.getMode() != AppOpsManager.MODE_ALLOWED) { + appInfos.add(new AppInfo.Builder() + .setPackageName(packageOps.getPackageName()) + .setUid(packageOps.getUid()) + .build()); + } + } + } + + return appInfos; + } + /** * Get a corresponding action based on {@code batteryTip} * @param batteryTip used to detect which action to choose diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java new file mode 100644 index 00000000000..8b4c017d1e9 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryManagerPreferenceControllerTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 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.batterytip; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.app.AppOpsManager; +import android.content.Context; +import android.provider.Settings; +import android.support.v7.preference.Preference; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +@RunWith(SettingsRobolectricTestRunner.class) +public class BatteryManagerPreferenceControllerTest { + private static final int ON = 1; + private static final int OFF = 0; + + @Mock + private AppOpsManager mAppOpsManager; + + + private Context mContext; + private Preference mPreference; + private FakeFeatureFactory mFeatureFactory; + private BatteryManagerPreferenceController mController; + + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + mPreference = new Preference(mContext); + mController = new BatteryManagerPreferenceController(mContext); + } + + @Test + public void updateState_smartBatteryOnWithRestrictApps_showSummary() { + mController.updateSummary(mPreference, true /* smartBatteryOn */, 2); + + assertThat(mPreference.getSummary()).isEqualTo("2 apps restricted"); + } + + @Test + public void updateState_smartBatteryOnWithoutRestriction_showSummary() { + when(mFeatureFactory.powerUsageFeatureProvider.isSmartBatterySupported()).thenReturn(true); + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.APP_STANDBY_ENABLED, + ON); + + mController.updateState(mPreference); + + assertThat(mPreference.getSummary()).isEqualTo("On / Restricting apps automatically"); + } + + @Test + public void updateState_smartBatteryOff_showSummary() { + when(mFeatureFactory.powerUsageFeatureProvider.isSmartBatterySupported()).thenReturn(true); + Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.APP_STANDBY_ENABLED, + OFF); + + mController.updateState(mPreference); + + assertThat(mPreference.getSummary()).isEqualTo("Off"); + } +}