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