diff --git a/res/xml/restricted_apps_detail.xml b/res/xml/restricted_apps_detail.xml new file mode 100644 index 00000000000..1e08a7edcb1 --- /dev/null +++ b/res/xml/restricted_apps_detail.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java b/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java index 6323715355f..8286774226a 100644 --- a/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceController.java @@ -54,9 +54,10 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo private final int mUid; @VisibleForTesting DevicePolicyManagerWrapper mDpm; + @VisibleForTesting + BatteryUtils mBatteryUtils; private Fragment mFragment; private String mTargetPackage; - private boolean mIsPreOApp; private PowerWhitelistBackend mPowerWhitelistBackend; public BackgroundActivityPreferenceController(Context context, Fragment fragment, @@ -77,7 +78,7 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo mUid = uid; mFragment = fragment; mTargetPackage = packageName; - mIsPreOApp = isLegacyApp(packageName); + mBatteryUtils = BatteryUtils.getInstance(context); } @Override @@ -109,12 +110,7 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo * activity for this package */ public void setUnchecked(Preference preference) { - if (mIsPreOApp) { - mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage, - AppOpsManager.MODE_IGNORED); - } - mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage, - AppOpsManager.MODE_IGNORED); + mBatteryUtils.setForceAppStandby(mUid, mTargetPackage, AppOpsManager.MODE_IGNORED); ((SwitchPreference) preference).setChecked(false); updateSummary(preference); } @@ -133,30 +129,11 @@ public class BackgroundActivityPreferenceController extends AbstractPreferenceCo dialogFragment.show(mFragment.getFragmentManager(), TAG); return false; } - if (mIsPreOApp) { - mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, mUid, mTargetPackage, - AppOpsManager.MODE_ALLOWED); - } - mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mTargetPackage, - AppOpsManager.MODE_ALLOWED); + mBatteryUtils.setForceAppStandby(mUid, mTargetPackage, AppOpsManager.MODE_ALLOWED); updateSummary(preference); return true; } - @VisibleForTesting - boolean isLegacyApp(final String packageName) { - try { - ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, - PackageManager.GET_META_DATA); - - return info.targetSdkVersion < Build.VERSION_CODES.O; - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Cannot find package: " + packageName, e); - } - - return false; - } - @VisibleForTesting void updateSummary(Preference preference) { if (mPowerWhitelistBackend.isWhitelisted(mTargetPackage)) { diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index 0952f1f095d..5738c290eb3 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -398,6 +398,19 @@ public class BatteryUtils { return timeMs * 1000; } + public void setForceAppStandby(int uid, String packageName, + int mode) { + final boolean isPreOApp = isLegacyApp(packageName); + if (isPreOApp) { + // Control whether app could run in the background if it is pre O app + mAppOpsManager.setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName, + mode); + } + // Control whether app could run jobs in the background + mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, + mode); + } + public void initBatteryStatsHelper(BatteryStatsHelper statsHelper, Bundle bundle, UserManager userManager) { statsHelper.create(bundle); @@ -481,5 +494,18 @@ public class BatteryUtils { return 0; } + public boolean isLegacyApp(final String packageName) { + try { + ApplicationInfo info = mPackageManager.getApplicationInfo(packageName, + PackageManager.GET_META_DATA); + + return info.targetSdkVersion < Build.VERSION_CODES.O; + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Cannot find package: " + packageName, e); + } + + return false; + } + } diff --git a/src/com/android/settings/fuelgauge/RestrictAppPreferenceController.java b/src/com/android/settings/fuelgauge/RestrictAppPreferenceController.java index 7df0fb1b79a..0a40f1ee89e 100644 --- a/src/com/android/settings/fuelgauge/RestrictAppPreferenceController.java +++ b/src/com/android/settings/fuelgauge/RestrictAppPreferenceController.java @@ -20,9 +20,11 @@ package com.android.settings.fuelgauge; import android.app.AppOpsManager; import android.content.Context; import android.support.annotation.VisibleForTesting; +import android.support.v14.preference.PreferenceFragment; import android.support.v7.preference.Preference; import com.android.settings.R; +import com.android.settings.SettingsActivity; import com.android.settings.applications.LayoutPreference; import com.android.settings.core.BasePreferenceController; @@ -37,12 +39,21 @@ public class RestrictAppPreferenceController extends BasePreferenceController { private AppOpsManager mAppOpsManager; private List mPackageOps; + private SettingsActivity mSettingsActivity; + private PreferenceFragment mPreferenceFragment; public RestrictAppPreferenceController(Context context) { super(context, KEY_RESTRICT_APP); mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); } + public RestrictAppPreferenceController(SettingsActivity settingsActivity, + PreferenceFragment preferenceFragment) { + this(settingsActivity.getApplicationContext()); + mSettingsActivity = settingsActivity; + mPreferenceFragment = preferenceFragment; + } + @Override public int getAvailabilityStatus() { return AVAILABLE; @@ -51,13 +62,27 @@ public class RestrictAppPreferenceController extends BasePreferenceController { @Override public void updateState(Preference preference) { super.updateState(preference); + mPackageOps = mAppOpsManager.getPackagesForOps( new int[]{AppOpsManager.OP_RUN_ANY_IN_BACKGROUND}); final int num = mPackageOps != null ? mPackageOps.size() : 0; + // Enable the preference if some apps already been restricted, otherwise disable it + preference.setEnabled(num > 0); preference.setSummary( mContext.getResources().getQuantityString(R.plurals.restricted_app_summary, num, num)); } + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (getPreferenceKey().equals(preference.getKey())) { + // start fragment + RestrictedAppDetails.startRestrictedAppDetails(mSettingsActivity, mPreferenceFragment, + mPackageOps); + return true; + } + + return super.handlePreferenceTreeClick(preference); + } } diff --git a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java new file mode 100644 index 00000000000..bdaaa3a66a9 --- /dev/null +++ b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java @@ -0,0 +1,147 @@ +/* + * 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; + +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.UserHandle; +import android.support.v14.preference.PreferenceFragment; +import android.support.v14.preference.SwitchPreference; +import android.support.v7.preference.CheckBoxPreference; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceGroup; +import android.util.IconDrawableFactory; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.Utils; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.fuelgauge.anomaly.Anomaly; +import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment; +import com.android.settings.fuelgauge.anomaly.AnomalyPreference; +import com.android.settingslib.core.AbstractPreferenceController; + +import java.util.List; + +/** + * Fragment to show a list of anomaly apps, where user could handle these anomalies + */ +public class RestrictedAppDetails extends DashboardFragment { + + public static final String TAG = "RestrictedAppDetails"; + + private static final String EXTRA_PACKAGE_OPS_LIST = "package_ops_list"; + private static final String KEY_PREF_RESTRICTED_APP_LIST = "restrict_app_list"; + + @VisibleForTesting + List mPackageOpsList; + @VisibleForTesting + IconDrawableFactory mIconDrawableFactory; + @VisibleForTesting + PreferenceGroup mRestrictedAppListGroup; + @VisibleForTesting + BatteryUtils mBatteryUtils; + @VisibleForTesting + PackageManager mPackageManager; + + public static void startRestrictedAppDetails(SettingsActivity caller, + PreferenceFragment fragment, List packageOpsList) { + Bundle args = new Bundle(); + args.putParcelableList(EXTRA_PACKAGE_OPS_LIST, packageOpsList); + + caller.startPreferencePanelAsUser(fragment, RestrictedAppDetails.class.getName(), args, + R.string.restricted_app_title, null /* titleText */, + new UserHandle(UserHandle.myUserId())); + } + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + final Context context = getContext(); + + mRestrictedAppListGroup = (PreferenceGroup) findPreference(KEY_PREF_RESTRICTED_APP_LIST); + mPackageOpsList = getArguments().getParcelableArrayList(EXTRA_PACKAGE_OPS_LIST); + mPackageManager = context.getPackageManager(); + mIconDrawableFactory = IconDrawableFactory.newInstance(context); + mBatteryUtils = BatteryUtils.getInstance(context); + + refreshUi(); + } + + @Override + public boolean onPreferenceTreeClick(Preference preference) { + + return super.onPreferenceTreeClick(preference); + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.restricted_apps_detail; + } + + @Override + protected List getPreferenceControllers(Context context) { + return null; + } + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.FUELGAUGE_RESTRICTED_APP_DETAILS; + } + + @VisibleForTesting + void refreshUi() { + mRestrictedAppListGroup.removeAll(); + final Context context = getPrefContext(); + + for (int i = 0, size = mPackageOpsList.size(); i < size; i++) { + final CheckBoxPreference checkBoxPreference = new CheckBoxPreference(context); + final AppOpsManager.PackageOps packageOps = mPackageOpsList.get(i); + try { + final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo( + packageOps.getPackageName(), 0 /* flags */); + checkBoxPreference.setChecked(true); + checkBoxPreference.setTitle(mPackageManager.getApplicationLabel(applicationInfo)); + checkBoxPreference.setKey(packageOps.getPackageName()); + checkBoxPreference.setOnPreferenceChangeListener((pref, value) -> { + // change the toggle + final int mode = (Boolean) value ? AppOpsManager.MODE_IGNORED + : AppOpsManager.MODE_ALLOWED; + final String packageName = pref.getKey(); + final int uid = mBatteryUtils.getPackageUid(packageName); + mBatteryUtils.setForceAppStandby(uid, packageName, mode); + return true; + }); + mRestrictedAppListGroup.addPreference(checkBoxPreference); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/src/com/android/settings/fuelgauge/SmartBatterySettings.java b/src/com/android/settings/fuelgauge/SmartBatterySettings.java index 5faaef41f60..52c0cef6b2e 100644 --- a/src/com/android/settings/fuelgauge/SmartBatterySettings.java +++ b/src/com/android/settings/fuelgauge/SmartBatterySettings.java @@ -19,9 +19,11 @@ package com.android.settings.fuelgauge; import android.content.Context; import android.os.Bundle; import android.provider.SearchIndexableResource; +import android.support.v14.preference.PreferenceFragment; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; +import com.android.settings.SettingsActivity; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; @@ -63,14 +65,20 @@ public class SmartBatterySettings extends DashboardFragment { @Override protected List getPreferenceControllers(Context context) { - return buildPreferenceControllers(context); + return buildPreferenceControllers(context, (SettingsActivity) getActivity(), this); } private static List buildPreferenceControllers( - Context context) { + Context context, SettingsActivity settingsActivity, PreferenceFragment fragment) { final List controllers = new ArrayList<>(); controllers.add(new SmartBatteryPreferenceController(context)); - controllers.add(new RestrictAppPreferenceController(context)); + if (settingsActivity != null && fragment != null) { + controllers.add( + new RestrictAppPreferenceController(settingsActivity, fragment)); + } else { + controllers.add(new RestrictAppPreferenceController(context)); + } + return controllers; } @@ -92,7 +100,7 @@ public class SmartBatterySettings extends DashboardFragment { @Override public List getPreferenceControllers( Context context) { - return buildPreferenceControllers(context); + return buildPreferenceControllers(context, null, null); } }; } diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider index ebcea43a42a..be910e105f3 100644 --- a/tests/robotests/assets/grandfather_not_implementing_index_provider +++ b/tests/robotests/assets/grandfather_not_implementing_index_provider @@ -24,3 +24,4 @@ com.android.settings.wifi.tether.WifiTetherSettings com.android.settings.wifi.SavedAccessPointsWifiSettings com.android.settings.notification.ZenModeEventRuleSettings com.android.settings.notification.ZenModeScheduleRuleSettings +com.android.settings.fuelgauge.RestrictedAppDetails diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java index 3d04ac51d64..0c9e394ffdd 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BackgroundActivityPreferenceControllerTest.java @@ -18,6 +18,10 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -38,6 +42,7 @@ import android.widget.Button; import com.android.settings.R; import com.android.settings.TestConfig; +import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settings.wrapper.DevicePolicyManagerWrapper; @@ -94,12 +99,14 @@ public class BackgroundActivityPreferenceControllerTest { private BackgroundActivityPreferenceController mController; private SwitchPreference mPreference; private Context mShadowContext; + private BatteryUtils mBatteryUtils; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mShadowContext = RuntimeEnvironment.application; + FakeFeatureFactory.setupForTest(); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); @@ -115,21 +122,22 @@ public class BackgroundActivityPreferenceControllerTest { mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O; mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L; + mBatteryUtils = spy(new BatteryUtils(mShadowContext)); + doNothing().when(mBatteryUtils).setForceAppStandby(anyInt(), anyString(), anyInt()); + mPreference = new SwitchPreference(mShadowContext); mController = spy(new BackgroundActivityPreferenceController( mContext, mFragment, UID_LOW_SDK, LOW_SDK_PACKAGE, mPowerWhitelistBackend)); mController.mDpm = mDevicePolicyManagerWrapper; + mController.mBatteryUtils = mBatteryUtils; } @Test public void testOnPreferenceChange_TurnOnCheck_MethodInvoked() { mController.onPreferenceChange(mPreference, true); - verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_LOW_SDK, - LOW_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED); - verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_LOW_SDK, - LOW_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED); - + verify(mBatteryUtils).setForceAppStandby(UID_LOW_SDK, LOW_SDK_PACKAGE, + AppOpsManager.MODE_ALLOWED); assertThat(mPreference.getSummary()) .isEqualTo(mShadowContext.getText(R.string.background_activity_summary_on)); } @@ -138,11 +146,12 @@ public class BackgroundActivityPreferenceControllerTest { public void testOnPreferenceChange_TurnOnCheckHighSDK_MethodInvoked() { mController = new BackgroundActivityPreferenceController(mContext, mFragment, UID_HIGH_SDK, HIGH_SDK_PACKAGE, mPowerWhitelistBackend); + mController.mBatteryUtils = mBatteryUtils; + mController.onPreferenceChange(mPreference, true); - verify(mAppOpsManager).setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, UID_HIGH_SDK, - HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED); - verify(mAppOpsManager, never()).setMode(AppOpsManager.OP_RUN_IN_BACKGROUND, UID_HIGH_SDK, - HIGH_SDK_PACKAGE, AppOpsManager.MODE_ALLOWED); + + verify(mBatteryUtils).setForceAppStandby(UID_HIGH_SDK, HIGH_SDK_PACKAGE, + AppOpsManager.MODE_ALLOWED); assertThat(mPreference.getSummary()) .isEqualTo(mShadowContext.getText(R.string.background_activity_summary_on)); } @@ -216,16 +225,6 @@ public class BackgroundActivityPreferenceControllerTest { assertThat(mPreference.getSummary()).isEqualTo(expectedSummary); } - @Test - public void testIsLegacyApp_SdkLowerThanO_ReturnTrue() { - assertThat(mController.isLegacyApp(LOW_SDK_PACKAGE)).isTrue(); - } - - @Test - public void testIsLegacyApp_SdkLargerOrEqualThanO_ReturnFalse() { - assertThat(mController.isLegacyApp(HIGH_SDK_PACKAGE)).isFalse(); - } - @Test public void testIsAvailable_ReturnTrue() { assertThat(mController.isAvailable()).isTrue(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index 844aca4c4a5..fe907510117 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -103,6 +103,8 @@ public class BatteryUtilsTest { private static final double PRECISION = 0.001; private static final int SDK_VERSION = Build.VERSION_CODES.L; private static final String PACKAGE_NAME = "com.android.app"; + private static final String HIGH_SDK_PACKAGE = "com.android.package.high"; + private static final String LOW_SDK_PACKAGE = "com.android.package.low"; @Mock private BatteryStats.Uid mUid; @@ -137,16 +139,18 @@ public class BatteryUtilsTest { @Mock private ApplicationInfo mApplicationInfo; @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private Context mContext; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) private BatteryStatsHelper mBatteryStatsHelper; + @Mock + private ApplicationInfo mHighApplicationInfo; + @Mock + private ApplicationInfo mLowApplicationInfo; private BatteryUtils mBatteryUtils; private FakeFeatureFactory mFeatureFactory; private PowerUsageFeatureProvider mProvider; private List mUsageList; @Before - public void setUp() { + public void setUp() throws PackageManager.NameNotFoundException { MockitoAnnotations.initMocks(this); mFeatureFactory = FakeFeatureFactory.setupForTest(); @@ -165,6 +169,14 @@ public class BatteryUtilsTest { when(mBatteryStatsHelper.getStats().computeBatteryRealtime(anyLong(), anyInt())).thenReturn( TIME_SINCE_LAST_FULL_CHARGE_US); + when(mPackageManager.getApplicationInfo(HIGH_SDK_PACKAGE, PackageManager.GET_META_DATA)) + .thenReturn(mHighApplicationInfo); + when(mPackageManager.getApplicationInfo(LOW_SDK_PACKAGE, PackageManager.GET_META_DATA)) + .thenReturn(mLowApplicationInfo); + mHighApplicationInfo.targetSdkVersion = Build.VERSION_CODES.O; + mLowApplicationInfo.targetSdkVersion = Build.VERSION_CODES.L; + + mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; mNormalBatterySipper.totalPowerMah = TOTAL_BATTERY_USAGE; @@ -501,4 +513,14 @@ public class BatteryUtilsTest { assertThat(mBatteryUtils.calculateScreenUsageTime(mBatteryStatsHelper)).isEqualTo( TIME_EXPECTED_FOREGROUND); } + + @Test + public void testIsLegacyApp_SdkLowerThanO_ReturnTrue() { + assertThat(mBatteryUtils.isLegacyApp(LOW_SDK_PACKAGE)).isTrue(); + } + + @Test + public void testIsLegacyApp_SdkLargerOrEqualThanO_ReturnFalse() { + assertThat(mBatteryUtils.isLegacyApp(HIGH_SDK_PACKAGE)).isFalse(); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java index c9441487b32..5e43d1d7bd5 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java @@ -19,13 +19,18 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import android.app.AppOpsManager; import android.content.Context; +import android.support.v14.preference.PreferenceFragment; import android.support.v7.preference.Preference; +import com.android.settings.R; +import com.android.settings.SettingsActivity; import com.android.settings.TestConfig; import org.junit.Before; @@ -48,6 +53,10 @@ public class RestrictAppPreferenceControllerTest { private AppOpsManager mAppOpsManager; @Mock private AppOpsManager.PackageOps mPackageOps; + @Mock + private SettingsActivity mSettingsActivity; + @Mock + private PreferenceFragment mFragment; private List mPackageOpsList; private RestrictAppPreferenceController mRestrictAppPreferenceController; private Preference mPreference; @@ -59,9 +68,12 @@ public class RestrictAppPreferenceControllerTest { mContext = spy(RuntimeEnvironment.application); doReturn(mAppOpsManager).when(mContext).getSystemService(Context.APP_OPS_SERVICE); - mRestrictAppPreferenceController = new RestrictAppPreferenceController(mContext); + doReturn(mContext).when(mSettingsActivity).getApplicationContext(); + mRestrictAppPreferenceController = new RestrictAppPreferenceController(mSettingsActivity, + mFragment); mPackageOpsList = new ArrayList<>(); mPreference = new Preference(mContext); + mPreference.setKey(mRestrictAppPreferenceController.getPreferenceKey()); } @Test @@ -85,4 +97,22 @@ public class RestrictAppPreferenceControllerTest { assertThat(mPreference.getSummary()).isEqualTo("2 apps"); } + @Test + public void testUpdateState_zeroApp_disabled() { + doReturn(mPackageOpsList).when(mAppOpsManager).getPackagesForOps(any()); + + mRestrictAppPreferenceController.updateState(mPreference); + + assertThat(mPreference.isEnabled()).isFalse(); + } + + @Test + public void testHandlePreferenceTreeClick_startFragment() { + mRestrictAppPreferenceController.handlePreferenceTreeClick(mPreference); + + verify(mSettingsActivity).startPreferencePanelAsUser(eq(mFragment), + eq(RestrictedAppDetails.class.getName()), any(), eq(R.string.restricted_app_title), + any(), any()); + } + } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java new file mode 100644 index 00000000000..a9de06176b4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedAppDetailsTest.java @@ -0,0 +1,91 @@ +/* + * 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; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceCategory; +import android.support.v7.preference.PreferenceManager; + +import com.android.settings.TestConfig; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +import java.util.ArrayList; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class RestrictedAppDetailsTest { + private static final String PACKAGE_NAME = "com.android.app"; + private static final String APP_NAME = "app"; + private static final int UID = 1234; + @Mock + private PackageManager mPackageManager; + @Mock + private ApplicationInfo mApplicationInfo; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private PreferenceManager mPreferenceManager; + private RestrictedAppDetails mFragment; + private Context mContext; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = spy(RuntimeEnvironment.application); + mFragment = spy(new RestrictedAppDetails()); + + doReturn(mPreferenceManager).when(mFragment).getPreferenceManager(); + doReturn(mContext).when(mPreferenceManager).getContext(); + mFragment.mPackageManager = mPackageManager; + mFragment.mPackageOpsList = new ArrayList<>(); + mFragment.mPackageOpsList.add( + new AppOpsManager.PackageOps(PACKAGE_NAME, UID, null /* entries */)); + mFragment.mRestrictedAppListGroup = spy(new PreferenceCategory(mContext)); + doReturn(mPreferenceManager).when(mFragment.mRestrictedAppListGroup).getPreferenceManager(); + } + + @Test + public void testRefreshUi_displayPreference() throws Exception { + doReturn(mApplicationInfo).when(mPackageManager).getApplicationInfo(PACKAGE_NAME, 0); + doReturn(APP_NAME).when(mPackageManager).getApplicationLabel(mApplicationInfo); + + mFragment.refreshUi(); + + assertThat(mFragment.mRestrictedAppListGroup.getPreferenceCount()).isEqualTo(1); + final Preference preference = mFragment.mRestrictedAppListGroup.getPreference(0); + assertThat(preference.getKey()).isEqualTo(PACKAGE_NAME); + assertThat(preference.getTitle()).isEqualTo(APP_NAME); + } + +}