2 * Copyright (C) 2017 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.applications;
20 import static com.google.common.truth.Truth.assertThat;
21 import static org.mockito.Matchers.any;
22 import static org.mockito.Matchers.anyString;
23 import static org.mockito.Mockito.doReturn;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.spy;
27 import static org.mockito.Mockito.times;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.when;
31 import android.app.AlertDialog;
32 import android.app.admin.DevicePolicyManager;
33 import android.content.Context;
34 import android.content.pm.ApplicationInfo;
35 import android.content.pm.PackageInfo;
36 import android.content.pm.PackageManager;
37 import android.os.BatteryStats;
38 import android.os.UserManager;
39 import android.support.v7.preference.Preference;
40 import android.support.v7.preference.PreferenceManager;
41 import android.support.v7.preference.PreferenceScreen;
42 import android.view.View;
43 import android.widget.Button;
45 import com.android.internal.os.BatterySipper;
46 import com.android.internal.os.BatteryStatsHelper;
47 import com.android.settings.SettingsActivity;
48 import com.android.settings.SettingsRobolectricTestRunner;
49 import com.android.settings.TestConfig;
50 import com.android.settings.applications.instantapps.InstantAppButtonsController;
51 import com.android.settings.testutils.FakeFeatureFactory;
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;
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.util.ReflectionHelpers;
68 @RunWith(SettingsRobolectricTestRunner.class)
69 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
70 public final class InstalledAppDetailsTest {
72 private static final String PACKAGE_NAME = "test_package_name";
74 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
75 private Context mContext;
77 ApplicationFeatureProvider mApplicationFeatureProvider;
78 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
79 private UserManager mUserManager;
80 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
81 private SettingsActivity mActivity;
83 private DevicePolicyManager mDevicePolicyManager;
85 private Preference mBatteryPreference;
87 private BatterySipper mBatterySipper;
89 private BatteryStatsHelper mBatteryStatsHelper;
91 private BatteryStats.Uid mUid;
93 private PackageManager mPackageManager;
95 private InstalledAppDetails mAppDetail;
96 private Context mShadowContext;
100 MockitoAnnotations.initMocks(this);
102 mShadowContext = RuntimeEnvironment.application;
103 mAppDetail = spy(new InstalledAppDetails());
105 mBatterySipper.drainType = BatterySipper.DrainType.IDLE;
106 mBatterySipper.uidObj = mUid;
107 doReturn(mActivity).when(mAppDetail).getActivity();
108 doReturn(mShadowContext).when(mAppDetail).getContext();
109 doReturn(mPackageManager).when(mActivity).getPackageManager();
111 // Default to not considering any apps to be instant (individual tests can override this).
112 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
113 (InstantAppDataProvider) (i -> false));
117 public void shouldShowUninstallForAll_installForOneOtherUserOnly_shouldReturnTrue() {
118 when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
119 when(mUserManager.getUsers().size()).thenReturn(2);
120 ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
121 ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
122 final ApplicationInfo info = new ApplicationInfo();
124 final AppEntry appEntry = mock(AppEntry.class);
125 appEntry.info = info;
126 final PackageInfo packageInfo = mock(PackageInfo.class);
127 ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
129 assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isTrue();
133 public void shouldShowUninstallForAll_installForSelfOnly_shouldReturnFalse() {
134 when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
135 when(mUserManager.getUsers().size()).thenReturn(2);
136 ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
137 ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
138 final ApplicationInfo info = new ApplicationInfo();
139 info.flags = ApplicationInfo.FLAG_INSTALLED;
141 final AppEntry appEntry = mock(AppEntry.class);
142 appEntry.info = info;
143 final PackageInfo packageInfo = mock(PackageInfo.class);
144 ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
146 assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
150 public void getStorageSummary_shouldWorkForExternal() {
151 Context context = RuntimeEnvironment.application.getApplicationContext();
152 AppStorageStats stats = mock(AppStorageStats.class);
153 when(stats.getTotalBytes()).thenReturn(1L);
155 assertThat(InstalledAppDetails.getStorageSummary(context, stats, true))
156 .isEqualTo("1.00B used in external storage");
160 public void getStorageSummary_shouldWorkForInternal() {
161 Context context = RuntimeEnvironment.application.getApplicationContext();
162 AppStorageStats stats = mock(AppStorageStats.class);
163 when(stats.getTotalBytes()).thenReturn(1L);
165 assertThat(InstalledAppDetails.getStorageSummary(context, stats, false))
166 .isEqualTo("1.00B used in internal storage");
170 public void launchFragment_hasNoPackageInfo_shouldFinish() {
171 ReflectionHelpers.setField(mAppDetail, "mPackageInfo", null);
173 assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isFalse();
174 verify(mActivity).finishAndRemoveTask();
178 public void launchFragment_hasPackageInfo_shouldReturnTrue() {
179 final PackageInfo packageInfo = mock(PackageInfo.class);
180 ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
182 assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isTrue();
183 verify(mActivity, never()).finishAndRemoveTask();
187 public void packageSizeChange_isOtherPackage_shouldNotRefreshUi() {
188 ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
189 mAppDetail.onPackageSizeChanged("Not_" + PACKAGE_NAME);
191 verify(mAppDetail, never()).refreshUi();
195 public void packageSizeChange_isOwnPackage_shouldRefreshUi() {
196 doReturn(Boolean.TRUE).when(mAppDetail).refreshUi();
197 ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
199 mAppDetail.onPackageSizeChanged(PACKAGE_NAME);
201 verify(mAppDetail).refreshUi();
205 public void launchPowerUsageDetailFragment_shouldNotCrash() {
206 mAppDetail.mBatteryPreference = mBatteryPreference;
207 mAppDetail.mSipper = mBatterySipper;
208 mAppDetail.mBatteryHelper = mBatteryStatsHelper;
211 mAppDetail.onPreferenceClick(mBatteryPreference);
214 // Tests that we don't show the "uninstall for all users" button for instant apps.
216 public void instantApps_noUninstallForAllButton() {
217 // Make this app appear to be instant.
218 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
219 (InstantAppDataProvider) (i -> true));
220 when(mDevicePolicyManager.packageHasActiveAdmins(anyString())).thenReturn(false);
221 when(mUserManager.getUsers().size()).thenReturn(2);
223 final ApplicationInfo info = new ApplicationInfo();
225 final AppEntry appEntry = mock(AppEntry.class);
226 appEntry.info = info;
227 final PackageInfo packageInfo = mock(PackageInfo.class);
229 ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
230 ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
231 ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
233 assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
236 // Tests that we don't show the uninstall button for instant apps"
238 public void instantApps_noUninstallButton() {
239 // Make this app appear to be instant.
240 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
241 (InstantAppDataProvider) (i -> true));
242 final ApplicationInfo info = new ApplicationInfo();
243 info.flags = ApplicationInfo.FLAG_INSTALLED;
245 final AppEntry appEntry = mock(AppEntry.class);
246 appEntry.info = info;
247 final PackageInfo packageInfo = mock(PackageInfo.class);
248 packageInfo.applicationInfo = info;
249 final Button uninstallButton = mock(Button.class);
251 ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
252 ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
253 ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
254 ReflectionHelpers.setField(mAppDetail, "mUninstallButton", uninstallButton);
256 mAppDetail.initUnintsallButtonForUserApp();
257 verify(uninstallButton).setVisibility(View.GONE);
260 // Tests that we don't show the force stop button for instant apps (they aren't allowed to run
261 // when they aren't in the foreground).
263 public void instantApps_noForceStop() {
264 // Make this app appear to be instant.
265 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
266 (InstantAppDataProvider) (i -> true));
267 final PackageInfo packageInfo = mock(PackageInfo.class);
268 final AppEntry appEntry = mock(AppEntry.class);
269 final ApplicationInfo info = new ApplicationInfo();
270 appEntry.info = info;
271 final Button forceStopButton = mock(Button.class);
273 ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
274 ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
275 ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
276 ReflectionHelpers.setField(mAppDetail, "mForceStopButton", forceStopButton);
278 mAppDetail.checkForceStop();
279 verify(forceStopButton).setVisibility(View.GONE);
283 public void instantApps_buttonControllerHandlesDialog() {
284 InstantAppButtonsController mockController = mock(InstantAppButtonsController.class);
285 ReflectionHelpers.setField(
286 mAppDetail, "mInstantAppButtonsController", mockController);
287 // Make sure first that button controller is not called for supported dialog id
288 AlertDialog mockDialog = mock(AlertDialog.class);
289 when(mockController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
290 .thenReturn(mockDialog);
291 assertThat(mAppDetail.createDialog(InstantAppButtonsController.DLG_CLEAR_APP, 0))
292 .isEqualTo(mockDialog);
293 verify(mockController).createDialog(InstantAppButtonsController.DLG_CLEAR_APP);
296 // A helper class for testing the InstantAppButtonsController - it lets us look up the
297 // preference associated with a key for instant app buttons and get back a mock
298 // LayoutPreference (to avoid a null pointer exception).
299 public static class InstalledAppDetailsWithMockInstantButtons extends InstalledAppDetails {
301 private LayoutPreference mInstantButtons;
303 public InstalledAppDetailsWithMockInstantButtons() {
305 MockitoAnnotations.initMocks(this);
309 public Preference findPreference(CharSequence key) {
310 if (key == "instant_app_buttons") {
311 return mInstantButtons;
313 return super.findPreference(key);
318 public void instantApps_instantSpecificButtons() {
319 // Make this app appear to be instant.
320 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
321 (InstantAppDataProvider) (i -> true));
322 final PackageInfo packageInfo = mock(PackageInfo.class);
324 final InstalledAppDetailsWithMockInstantButtons
325 fragment = new InstalledAppDetailsWithMockInstantButtons();
326 ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
328 final InstantAppButtonsController buttonsController =
329 mock(InstantAppButtonsController.class);
330 when(buttonsController.setPackageName(anyString())).thenReturn(buttonsController);
332 FakeFeatureFactory.setupForTest(mContext);
333 FakeFeatureFactory factory =
334 (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
335 when(factory.applicationFeatureProvider.newInstantAppButtonsController(
336 any(), any(), any())).thenReturn(buttonsController);
338 fragment.maybeAddInstantAppButtons();
339 verify(buttonsController).setPackageName(anyString());
340 verify(buttonsController).show();
344 public void instantApps_removeCorrectPref() {
345 PreferenceScreen mockPreferenceScreen = mock(PreferenceScreen.class);
346 PreferenceManager mockPreferenceManager = mock(PreferenceManager.class);
347 AppDomainsPreference mockAppDomainsPref = mock(AppDomainsPreference.class);
348 Preference mockLaunchPreference = mock(Preference.class);
349 PackageInfo mockPackageInfo = mock(PackageInfo.class);
350 PackageManager mockPackageManager = mock(PackageManager.class);
351 ReflectionHelpers.setField(
352 mAppDetail, "mLaunchPreference", mockLaunchPreference);
353 ReflectionHelpers.setField(
354 mAppDetail, "mInstantAppDomainsPreference", mockAppDomainsPref);
355 ReflectionHelpers.setField(
356 mAppDetail, "mPreferenceManager", mockPreferenceManager);
357 ReflectionHelpers.setField(
358 mAppDetail, "mPackageInfo", mockPackageInfo);
359 ReflectionHelpers.setField(
360 mAppDetail, "mPm", mockPackageManager);
361 when(mockPreferenceManager.getPreferenceScreen()).thenReturn(mockPreferenceScreen);
363 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
364 (InstantAppDataProvider) (i -> false));
365 mAppDetail.prepareInstantAppPrefs();
367 // For the non instant case we remove the app domain pref, and leave the launch pref
368 verify(mockPreferenceScreen).removePreference(mockAppDomainsPref);
369 verify(mockPreferenceScreen, never()).removePreference(mockLaunchPreference);
371 // For the instant app case we remove the launch preff, and leave the app domain pref
372 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
373 (InstantAppDataProvider) (i -> true));
375 mAppDetail.prepareInstantAppPrefs();
376 verify(mockPreferenceScreen).removePreference(mockLaunchPreference);
377 // Will be 1 still due to above call
378 verify(mockPreferenceScreen, times(1))
379 .removePreference(mockAppDomainsPref);