• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.applications;
18 
19 import android.app.AlertDialog;
20 import android.app.LoaderManager;
21 import android.app.admin.DevicePolicyManager;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageInfo;
26 import android.content.pm.PackageManager;
27 import android.content.res.Resources;
28 import android.os.BatteryStats;
29 import android.os.Bundle;
30 import android.os.UserManager;
31 import android.support.v7.preference.Preference;
32 import android.support.v7.preference.PreferenceManager;
33 import android.support.v7.preference.PreferenceScreen;
34 import android.view.View;
35 import android.widget.Button;
36 
37 import com.android.internal.os.BatterySipper;
38 import com.android.internal.os.BatteryStatsHelper;
39 import com.android.settings.R;
40 import com.android.settings.SettingsActivity;
41 import com.android.settings.SettingsRobolectricTestRunner;
42 import com.android.settings.TestConfig;
43 import com.android.settings.applications.instantapps.InstantAppButtonsController;
44 import com.android.settings.fuelgauge.BatteryUtils;
45 import com.android.settings.testutils.FakeFeatureFactory;
46 import com.android.settingslib.Utils;
47 import com.android.settingslib.applications.AppUtils;
48 import com.android.settingslib.applications.ApplicationsState.AppEntry;
49 import com.android.settingslib.applications.StorageStatsSource.AppStorageStats;
50 import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
51 
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.Answers;
56 import org.mockito.Mock;
57 import org.mockito.MockitoAnnotations;
58 import org.robolectric.RuntimeEnvironment;
59 import org.robolectric.annotation.Config;
60 import org.robolectric.annotation.Implementation;
61 import org.robolectric.annotation.Implements;
62 import org.robolectric.util.ReflectionHelpers;
63 
64 import java.util.ArrayList;
65 import java.util.HashSet;
66 import java.util.List;
67 
68 import static com.google.common.truth.Truth.assertThat;
69 import static org.mockito.Matchers.any;
70 import static org.mockito.Matchers.anyDouble;
71 import static org.mockito.Matchers.anyInt;
72 import static org.mockito.Matchers.anyString;
73 import static org.mockito.Mockito.doReturn;
74 import static org.mockito.Mockito.mock;
75 import static org.mockito.Mockito.never;
76 import static org.mockito.Mockito.spy;
77 import static org.mockito.Mockito.times;
78 import static org.mockito.Mockito.verify;
79 import static org.mockito.Mockito.when;
80 
81 
82 @RunWith(SettingsRobolectricTestRunner.class)
83 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
84 public final class InstalledAppDetailsTest {
85 
86     private static final String PACKAGE_NAME = "test_package_name";
87     private static final int TARGET_UID = 111;
88     private static final int OTHER_UID = 222;
89     private static final double BATTERY_LEVEL = 60;
90     private static final String BATTERY_LEVEL_STRING = "60%";
91 
92     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
93     private Context mContext;
94     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
95     private UserManager mUserManager;
96     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
97     private SettingsActivity mActivity;
98     @Mock
99     private DevicePolicyManager mDevicePolicyManager;
100     @Mock
101     private BatterySipper mBatterySipper;
102     @Mock
103     private BatterySipper mOtherBatterySipper;
104     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
105     private BatteryStatsHelper mBatteryStatsHelper;
106     @Mock
107     private BatteryStats.Uid mUid;
108     @Mock
109     private PackageManager mPackageManager;
110     @Mock
111     private BatteryUtils mBatteryUtils;
112     @Mock
113     private LoaderManager mLoaderManager;
114 
115     private FakeFeatureFactory mFeatureFactory;
116     private InstalledAppDetails mAppDetail;
117     private Context mShadowContext;
118     private Preference mBatteryPreference;
119 
120 
121     @Before
setUp()122     public void setUp() {
123         MockitoAnnotations.initMocks(this);
124         FakeFeatureFactory.setupForTest(mContext);
125         mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
126         mShadowContext = RuntimeEnvironment.application;
127         mAppDetail = spy(new InstalledAppDetails());
128         mAppDetail.mBatteryUtils = mBatteryUtils;
129 
130         mBatteryPreference = new Preference(mShadowContext);
131         mAppDetail.mBatteryPreference = mBatteryPreference;
132 
133         mBatterySipper.drainType = BatterySipper.DrainType.IDLE;
134         mBatterySipper.uidObj = mUid;
135         doReturn(TARGET_UID).when(mBatterySipper).getUid();
136         doReturn(OTHER_UID).when(mOtherBatterySipper).getUid();
137         doReturn(mActivity).when(mAppDetail).getActivity();
138         doReturn(mShadowContext).when(mAppDetail).getContext();
139         doReturn(mPackageManager).when(mActivity).getPackageManager();
140 
141         // Default to not considering any apps to be instant (individual tests can override this).
142         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
143                 (InstantAppDataProvider) (i -> false));
144     }
145 
146     @Test
shouldShowUninstallForAll_installForOneOtherUserOnly_shouldReturnTrue()147     public void shouldShowUninstallForAll_installForOneOtherUserOnly_shouldReturnTrue() {
148         when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
149         when(mUserManager.getUsers().size()).thenReturn(2);
150         ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
151         ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
152         final ApplicationInfo info = new ApplicationInfo();
153         info.enabled = true;
154         final AppEntry appEntry = mock(AppEntry.class);
155         appEntry.info = info;
156         final PackageInfo packageInfo = mock(PackageInfo.class);
157         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
158 
159         assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isTrue();
160     }
161 
162     @Test
shouldShowUninstallForAll_installForSelfOnly_shouldReturnFalse()163     public void shouldShowUninstallForAll_installForSelfOnly_shouldReturnFalse() {
164         when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
165         when(mUserManager.getUsers().size()).thenReturn(2);
166         ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
167         ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
168         final ApplicationInfo info = new ApplicationInfo();
169         info.flags = ApplicationInfo.FLAG_INSTALLED;
170         info.enabled = true;
171         final AppEntry appEntry = mock(AppEntry.class);
172         appEntry.info = info;
173         final PackageInfo packageInfo = mock(PackageInfo.class);
174         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
175 
176         assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
177     }
178 
179     @Test
getStorageSummary_shouldWorkForExternal()180     public void getStorageSummary_shouldWorkForExternal() {
181         Context context = RuntimeEnvironment.application.getApplicationContext();
182         AppStorageStats stats = mock(AppStorageStats.class);
183         when(stats.getTotalBytes()).thenReturn(1L);
184 
185         assertThat(InstalledAppDetails.getStorageSummary(context, stats, true))
186                 .isEqualTo("1.00B used in external storage");
187     }
188 
189     @Test
getStorageSummary_shouldWorkForInternal()190     public void getStorageSummary_shouldWorkForInternal() {
191         Context context = RuntimeEnvironment.application.getApplicationContext();
192         AppStorageStats stats = mock(AppStorageStats.class);
193         when(stats.getTotalBytes()).thenReturn(1L);
194 
195         assertThat(InstalledAppDetails.getStorageSummary(context, stats, false))
196                 .isEqualTo("1.00B used in internal storage");
197     }
198 
199     @Test
launchFragment_hasNoPackageInfo_shouldFinish()200     public void launchFragment_hasNoPackageInfo_shouldFinish() {
201         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", null);
202 
203         assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isFalse();
204         verify(mActivity).finishAndRemoveTask();
205     }
206 
207     @Test
launchFragment_hasPackageInfo_shouldReturnTrue()208     public void launchFragment_hasPackageInfo_shouldReturnTrue() {
209         final PackageInfo packageInfo = mock(PackageInfo.class);
210         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
211 
212         assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isTrue();
213         verify(mActivity, never()).finishAndRemoveTask();
214     }
215 
216     @Test
packageSizeChange_isOtherPackage_shouldNotRefreshUi()217     public void packageSizeChange_isOtherPackage_shouldNotRefreshUi() {
218         ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
219         mAppDetail.onPackageSizeChanged("Not_" + PACKAGE_NAME);
220 
221         verify(mAppDetail, never()).refreshUi();
222     }
223 
224     @Test
packageSizeChange_isOwnPackage_shouldRefreshUi()225     public void packageSizeChange_isOwnPackage_shouldRefreshUi() {
226         doReturn(Boolean.TRUE).when(mAppDetail).refreshUi();
227         ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
228 
229         mAppDetail.onPackageSizeChanged(PACKAGE_NAME);
230 
231         verify(mAppDetail).refreshUi();
232     }
233 
234     @Test
launchPowerUsageDetailFragment_shouldNotCrash()235     public void launchPowerUsageDetailFragment_shouldNotCrash() {
236         mAppDetail.mBatteryPreference = mBatteryPreference;
237         mAppDetail.mSipper = mBatterySipper;
238         mAppDetail.mBatteryHelper = mBatteryStatsHelper;
239 
240         // Should not crash
241         mAppDetail.onPreferenceClick(mBatteryPreference);
242     }
243 
244     // Tests that we don't show the "uninstall for all users" button for instant apps.
245     @Test
instantApps_noUninstallForAllButton()246     public void instantApps_noUninstallForAllButton() {
247         // Make this app appear to be instant.
248         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
249                 (InstantAppDataProvider) (i -> true));
250         when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
251         when(mUserManager.getUsers().size()).thenReturn(2);
252 
253         final ApplicationInfo info = new ApplicationInfo();
254         info.enabled = true;
255         final AppEntry appEntry = mock(AppEntry.class);
256         appEntry.info = info;
257         final PackageInfo packageInfo = mock(PackageInfo.class);
258 
259         ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
260         ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
261         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
262 
263         assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
264     }
265 
266     // Tests that we don't show the uninstall button for instant apps"
267     @Test
instantApps_noUninstallButton()268     public void instantApps_noUninstallButton() {
269         // Make this app appear to be instant.
270         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
271                 (InstantAppDataProvider) (i -> true));
272         final ApplicationInfo info = new ApplicationInfo();
273         info.flags = ApplicationInfo.FLAG_INSTALLED;
274         info.enabled = true;
275         final AppEntry appEntry = mock(AppEntry.class);
276         appEntry.info = info;
277         final PackageInfo packageInfo = mock(PackageInfo.class);
278         packageInfo.applicationInfo = info;
279         final Button uninstallButton = mock(Button.class);
280 
281         ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
282         ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
283         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
284         ReflectionHelpers.setField(mAppDetail, "mUninstallButton", uninstallButton);
285 
286         mAppDetail.initUnintsallButtonForUserApp();
287         verify(uninstallButton).setVisibility(View.GONE);
288     }
289 
290     // Tests that we don't show the force stop button for instant apps (they aren't allowed to run
291     // when they aren't in the foreground).
292     @Test
instantApps_noForceStop()293     public void instantApps_noForceStop() {
294         // Make this app appear to be instant.
295         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
296                 (InstantAppDataProvider) (i -> true));
297         final PackageInfo packageInfo = mock(PackageInfo.class);
298         final AppEntry appEntry = mock(AppEntry.class);
299         final ApplicationInfo info = new ApplicationInfo();
300         appEntry.info = info;
301         final Button forceStopButton = mock(Button.class);
302 
303         ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
304         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
305         ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
306         ReflectionHelpers.setField(mAppDetail, "mForceStopButton", forceStopButton);
307 
308         mAppDetail.checkForceStop();
309         verify(forceStopButton).setVisibility(View.GONE);
310     }
311 
312     @Test
instantApps_buttonControllerHandlesDialog()313     public void instantApps_buttonControllerHandlesDialog() {
314         InstantAppButtonsController mockController = mock(InstantAppButtonsController.class);
315         ReflectionHelpers.setField(
316                 mAppDetail, "mInstantAppButtonsController", mockController);
317         // Make sure first that button controller is not called for supported dialog id
318         AlertDialog mockDialog = mock(AlertDialog.class);
319         when(mockController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
320                 .thenReturn(mockDialog);
321         assertThat(mAppDetail.createDialog(InstantAppButtonsController.DLG_CLEAR_APP, 0))
322                 .isEqualTo(mockDialog);
323         verify(mockController).createDialog(InstantAppButtonsController.DLG_CLEAR_APP);
324     }
325 
326     // A helper class for testing the InstantAppButtonsController - it lets us look up the
327     // preference associated with a key for instant app buttons and get back a mock
328     // LayoutPreference (to avoid a null pointer exception).
329     public static class InstalledAppDetailsWithMockInstantButtons extends InstalledAppDetails {
330         @Mock
331         private LayoutPreference mInstantButtons;
332 
InstalledAppDetailsWithMockInstantButtons()333         public InstalledAppDetailsWithMockInstantButtons() {
334             super();
335             MockitoAnnotations.initMocks(this);
336         }
337 
338         @Override
findPreference(CharSequence key)339         public Preference findPreference(CharSequence key) {
340             if (key == "instant_app_buttons") {
341                 return mInstantButtons;
342             }
343             return super.findPreference(key);
344         }
345     }
346 
347     @Test
instantApps_instantSpecificButtons()348     public void instantApps_instantSpecificButtons() {
349         // Make this app appear to be instant.
350         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
351                 (InstantAppDataProvider) (i -> true));
352         final PackageInfo packageInfo = mock(PackageInfo.class);
353 
354         final InstalledAppDetailsWithMockInstantButtons
355                 fragment = new InstalledAppDetailsWithMockInstantButtons();
356         ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
357         ReflectionHelpers.setField(fragment, "mApplicationFeatureProvider",
358                 mFeatureFactory.applicationFeatureProvider);
359 
360         final InstantAppButtonsController buttonsController =
361                 mock(InstantAppButtonsController.class);
362         when(buttonsController.setPackageName(anyString())).thenReturn(buttonsController);
363 
364         when(mFeatureFactory.applicationFeatureProvider.newInstantAppButtonsController(
365                 any(), any(), any())).thenReturn(buttonsController);
366 
367         fragment.maybeAddInstantAppButtons();
368         verify(buttonsController).setPackageName(anyString());
369         verify(buttonsController).show();
370     }
371 
372     @Test
instantApps_removeCorrectPref()373     public void instantApps_removeCorrectPref() {
374         PreferenceScreen mockPreferenceScreen = mock(PreferenceScreen.class);
375         PreferenceManager mockPreferenceManager = mock(PreferenceManager.class);
376         AppDomainsPreference mockAppDomainsPref = mock(AppDomainsPreference.class);
377         Preference mockLaunchPreference = mock(Preference.class);
378         PackageInfo mockPackageInfo = mock(PackageInfo.class);
379         PackageManager mockPackageManager = mock(PackageManager.class);
380         ReflectionHelpers.setField(
381                 mAppDetail, "mLaunchPreference", mockLaunchPreference);
382         ReflectionHelpers.setField(
383                 mAppDetail, "mInstantAppDomainsPreference", mockAppDomainsPref);
384         ReflectionHelpers.setField(
385                 mAppDetail, "mPreferenceManager", mockPreferenceManager);
386         ReflectionHelpers.setField(
387                 mAppDetail, "mPackageInfo", mockPackageInfo);
388         ReflectionHelpers.setField(
389                 mAppDetail, "mPm", mockPackageManager);
390         when(mockPreferenceManager.getPreferenceScreen()).thenReturn(mockPreferenceScreen);
391 
392         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
393                 (InstantAppDataProvider) (i -> false));
394         mAppDetail.prepareInstantAppPrefs();
395 
396         // For the non instant case we remove the app domain pref, and leave the launch pref
397         verify(mockPreferenceScreen).removePreference(mockAppDomainsPref);
398         verify(mockPreferenceScreen, never()).removePreference(mockLaunchPreference);
399 
400         // For the instant app case we remove the launch preff, and leave the app domain pref
401         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
402                 (InstantAppDataProvider) (i -> true));
403 
404         mAppDetail.prepareInstantAppPrefs();
405         verify(mockPreferenceScreen).removePreference(mockLaunchPreference);
406         // Will be 1 still due to above call
407         verify(mockPreferenceScreen, times(1))
408                 .removePreference(mockAppDomainsPref);
409     }
410 
411     @Test
onActivityResult_uninstalledUpdates_shouldInvalidateOptionsMenu()412     public void onActivityResult_uninstalledUpdates_shouldInvalidateOptionsMenu() {
413         doReturn(true).when(mAppDetail).refreshUi();
414 
415         mAppDetail.onActivityResult(InstalledAppDetails.REQUEST_UNINSTALL, 0, mock(Intent.class));
416 
417         verify(mActivity).invalidateOptionsMenu();
418     }
419 
420     @Test
findTargetSipper_findCorrectSipper()421     public void findTargetSipper_findCorrectSipper() {
422         List<BatterySipper> usageList = new ArrayList<>();
423         usageList.add(mBatterySipper);
424         usageList.add(mOtherBatterySipper);
425         doReturn(usageList).when(mBatteryStatsHelper).getUsageList();
426 
427         assertThat(mAppDetail.findTargetSipper(mBatteryStatsHelper, TARGET_UID)).isEqualTo(
428                 mBatterySipper);
429     }
430 
431     @Test
updateBattery_noBatteryStats_summaryNo()432     public void updateBattery_noBatteryStats_summaryNo() {
433         doReturn(mShadowContext.getString(R.string.no_battery_summary)).when(mAppDetail).getString(
434                 R.string.no_battery_summary);
435         mAppDetail.updateBattery();
436 
437         assertThat(mBatteryPreference.getSummary()).isEqualTo(
438                 "No battery use since last full charge");
439     }
440 
441     @Test
updateBattery_hasBatteryStats_summaryPercent()442     public void updateBattery_hasBatteryStats_summaryPercent() {
443         mAppDetail.mBatteryHelper = mBatteryStatsHelper;
444         mAppDetail.mSipper = mBatterySipper;
445         doReturn(BATTERY_LEVEL).when(mBatteryUtils).calculateBatteryPercent(anyDouble(),
446                 anyDouble(), anyDouble(), anyInt());
447         doReturn(mShadowContext.getString(R.string.battery_summary, BATTERY_LEVEL_STRING)).when(
448                 mAppDetail).getString(R.string.battery_summary, BATTERY_LEVEL_STRING);
449         doReturn(new ArrayList<>()).when(mBatteryStatsHelper).getUsageList();
450 
451         mAppDetail.updateBattery();
452 
453         assertThat(mBatteryPreference.getSummary()).isEqualTo("60% use since last full charge");
454     }
455 
456     @Test
isBatteryStatsAvailable_hasBatteryStatsHelperAndSipper_returnTrue()457     public void isBatteryStatsAvailable_hasBatteryStatsHelperAndSipper_returnTrue() {
458         mAppDetail.mBatteryHelper = mBatteryStatsHelper;
459         mAppDetail.mSipper = mBatterySipper;
460 
461         assertThat(mAppDetail.isBatteryStatsAvailable()).isTrue();
462     }
463 
464     @Test
isBatteryStatsAvailable_parametersNull_returnFalse()465     public void isBatteryStatsAvailable_parametersNull_returnFalse() {
466         assertThat(mAppDetail.isBatteryStatsAvailable()).isFalse();
467     }
468 
469     @Test
handleDisableable_appIsHomeApp_buttonShouldNotWork()470     public void handleDisableable_appIsHomeApp_buttonShouldNotWork() {
471         final ApplicationInfo info = new ApplicationInfo();
472         info.packageName = "pkg";
473         info.enabled = true;
474         final AppEntry appEntry = mock(AppEntry.class);
475         appEntry.info = info;
476         final HashSet<String> homePackages = new HashSet<>();
477         homePackages.add(info.packageName);
478 
479         ReflectionHelpers.setField(mAppDetail, "mHomePackages", homePackages);
480         ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
481         final Button button = mock(Button.class);
482 
483         assertThat(mAppDetail.handleDisableable(button)).isFalse();
484         verify(button).setText(R.string.disable_text);
485     }
486 
487     @Test
488     @Config(shadows = ShadowUtils.class)
handleDisableable_appIsEnabled_buttonShouldWork()489     public void handleDisableable_appIsEnabled_buttonShouldWork() {
490         final ApplicationInfo info = new ApplicationInfo();
491         info.packageName = "pkg";
492         info.enabled = true;
493         info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
494 
495         final AppEntry appEntry = mock(AppEntry.class);
496         appEntry.info = info;
497         when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
498                 new HashSet<>());
499 
500         ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
501                 mFeatureFactory.applicationFeatureProvider);
502         ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
503         final Button button = mock(Button.class);
504 
505         assertThat(mAppDetail.handleDisableable(button)).isTrue();
506         verify(button).setText(R.string.disable_text);
507     }
508 
509     @Test
510     @Config(shadows = ShadowUtils.class)
handleDisableable_appIsEnabledAndInKeepEnabledWhitelist_buttonShouldNotWork()511     public void handleDisableable_appIsEnabledAndInKeepEnabledWhitelist_buttonShouldNotWork() {
512         final ApplicationInfo info = new ApplicationInfo();
513         info.packageName = "pkg";
514         info.enabled = true;
515         info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
516 
517         final AppEntry appEntry = mock(AppEntry.class);
518         appEntry.info = info;
519 
520         final HashSet<String> packages = new HashSet<>();
521         packages.add(info.packageName);
522         when(mFeatureFactory.applicationFeatureProvider.getKeepEnabledPackages()).thenReturn(
523                 packages);
524 
525         ReflectionHelpers.setField(mAppDetail, "mApplicationFeatureProvider",
526                 mFeatureFactory.applicationFeatureProvider);
527         ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
528 
529         final Button button = mock(Button.class);
530 
531         assertThat(mAppDetail.handleDisableable(button)).isFalse();
532         verify(button).setText(R.string.disable_text);
533     }
534 
535     @Test
testRestartBatteryStatsLoader()536     public void testRestartBatteryStatsLoader() {
537         doReturn(mLoaderManager).when(mAppDetail).getLoaderManager();
538 
539         mAppDetail.restartBatteryStatsLoader();
540 
541         verify(mLoaderManager).restartLoader(InstalledAppDetails.LOADER_BATTERY, Bundle.EMPTY,
542                 mAppDetail.mBatteryCallbacks);
543     }
544 
545     @Implements(Utils.class)
546     public static class ShadowUtils {
547         @Implementation
isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg)548         public static boolean isSystemPackage(Resources resources, PackageManager pm,
549                 PackageInfo pkg) {
550             return false;
551         }
552     }
553 }
554