OSDN Git Service

Fix ANR in installed app details.
[android-x86/packages-apps-Settings.git] / tests / robotests / src / com / android / settings / applications / InstalledAppDetailsTest.java
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 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;
30
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;
44
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;
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.util.ReflectionHelpers;
66
67
68 @RunWith(SettingsRobolectricTestRunner.class)
69 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
70 public final class InstalledAppDetailsTest {
71
72     private static final String PACKAGE_NAME = "test_package_name";
73
74     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
75     private Context mContext;
76     @Mock
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;
82     @Mock
83     private DevicePolicyManager mDevicePolicyManager;
84     @Mock
85     private Preference mBatteryPreference;
86     @Mock
87     private BatterySipper mBatterySipper;
88     @Mock
89     private BatteryStatsHelper mBatteryStatsHelper;
90     @Mock
91     private BatteryStats.Uid mUid;
92     @Mock
93     private PackageManager mPackageManager;
94
95     private InstalledAppDetails mAppDetail;
96     private Context mShadowContext;
97
98     @Before
99     public void setUp() {
100         MockitoAnnotations.initMocks(this);
101
102         mShadowContext = RuntimeEnvironment.application;
103         mAppDetail = spy(new InstalledAppDetails());
104
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();
110
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));
114     }
115
116     @Test
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();
123         info.enabled = true;
124         final AppEntry appEntry = mock(AppEntry.class);
125         appEntry.info = info;
126         final PackageInfo packageInfo = mock(PackageInfo.class);
127         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
128
129         assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isTrue();
130     }
131
132     @Test
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;
140         info.enabled = true;
141         final AppEntry appEntry = mock(AppEntry.class);
142         appEntry.info = info;
143         final PackageInfo packageInfo = mock(PackageInfo.class);
144         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
145
146         assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
147     }
148
149     @Test
150     public void getStorageSummary_shouldWorkForExternal() {
151         Context context = RuntimeEnvironment.application.getApplicationContext();
152         AppStorageStats stats = mock(AppStorageStats.class);
153         when(stats.getTotalBytes()).thenReturn(1L);
154
155         assertThat(InstalledAppDetails.getStorageSummary(context, stats, true))
156                 .isEqualTo("1.00B used in external storage");
157     }
158
159     @Test
160     public void getStorageSummary_shouldWorkForInternal() {
161         Context context = RuntimeEnvironment.application.getApplicationContext();
162         AppStorageStats stats = mock(AppStorageStats.class);
163         when(stats.getTotalBytes()).thenReturn(1L);
164
165         assertThat(InstalledAppDetails.getStorageSummary(context, stats, false))
166                 .isEqualTo("1.00B used in internal storage");
167     }
168
169     @Test
170     public void launchFragment_hasNoPackageInfo_shouldFinish() {
171         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", null);
172
173         assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isFalse();
174         verify(mActivity).finishAndRemoveTask();
175     }
176
177     @Test
178     public void launchFragment_hasPackageInfo_shouldReturnTrue() {
179         final PackageInfo packageInfo = mock(PackageInfo.class);
180         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
181
182         assertThat(mAppDetail.ensurePackageInfoAvailable(mActivity)).isTrue();
183         verify(mActivity, never()).finishAndRemoveTask();
184     }
185
186     @Test
187     public void packageSizeChange_isOtherPackage_shouldNotRefreshUi() {
188         ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
189         mAppDetail.onPackageSizeChanged("Not_" + PACKAGE_NAME);
190
191         verify(mAppDetail, never()).refreshUi();
192     }
193
194     @Test
195     public void packageSizeChange_isOwnPackage_shouldRefreshUi() {
196         doReturn(Boolean.TRUE).when(mAppDetail).refreshUi();
197         ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
198
199         mAppDetail.onPackageSizeChanged(PACKAGE_NAME);
200
201         verify(mAppDetail).refreshUi();
202     }
203
204     @Test
205     public void launchPowerUsageDetailFragment_shouldNotCrash() {
206         mAppDetail.mBatteryPreference = mBatteryPreference;
207         mAppDetail.mSipper = mBatterySipper;
208         mAppDetail.mBatteryHelper = mBatteryStatsHelper;
209
210         // Should not crash
211         mAppDetail.onPreferenceClick(mBatteryPreference);
212     }
213
214     // Tests that we don't show the "uninstall for all users" button for instant apps.
215     @Test
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);
222
223         final ApplicationInfo info = new ApplicationInfo();
224         info.enabled = true;
225         final AppEntry appEntry = mock(AppEntry.class);
226         appEntry.info = info;
227         final PackageInfo packageInfo = mock(PackageInfo.class);
228
229         ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
230         ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
231         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
232
233         assertThat(mAppDetail.shouldShowUninstallForAll(appEntry)).isFalse();
234     }
235
236     // Tests that we don't show the uninstall button for instant apps"
237     @Test
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;
244         info.enabled = true;
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);
250
251         ReflectionHelpers.setField(mAppDetail, "mUserManager", mUserManager);
252         ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
253         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
254         ReflectionHelpers.setField(mAppDetail, "mUninstallButton", uninstallButton);
255
256         mAppDetail.initUnintsallButtonForUserApp();
257         verify(uninstallButton).setVisibility(View.GONE);
258     }
259
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).
262     @Test
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);
272
273         ReflectionHelpers.setField(mAppDetail, "mDpm", mDevicePolicyManager);
274         ReflectionHelpers.setField(mAppDetail, "mPackageInfo", packageInfo);
275         ReflectionHelpers.setField(mAppDetail, "mAppEntry", appEntry);
276         ReflectionHelpers.setField(mAppDetail, "mForceStopButton", forceStopButton);
277
278         mAppDetail.checkForceStop();
279         verify(forceStopButton).setVisibility(View.GONE);
280     }
281
282     @Test
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);
294     }
295
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 {
300         @Mock
301         private LayoutPreference mInstantButtons;
302
303         public InstalledAppDetailsWithMockInstantButtons() {
304             super();
305             MockitoAnnotations.initMocks(this);
306         }
307
308         @Override
309         public Preference findPreference(CharSequence key) {
310             if (key == "instant_app_buttons") {
311                 return mInstantButtons;
312             }
313             return super.findPreference(key);
314         }
315     }
316
317     @Test
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);
323
324         final InstalledAppDetailsWithMockInstantButtons
325                 fragment = new InstalledAppDetailsWithMockInstantButtons();
326         ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
327
328         final InstantAppButtonsController buttonsController =
329                 mock(InstantAppButtonsController.class);
330         when(buttonsController.setPackageName(anyString())).thenReturn(buttonsController);
331
332         FakeFeatureFactory.setupForTest(mContext);
333         FakeFeatureFactory factory =
334                 (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
335         when(factory.applicationFeatureProvider.newInstantAppButtonsController(
336                 any(), any(), any())).thenReturn(buttonsController);
337
338         fragment.maybeAddInstantAppButtons();
339         verify(buttonsController).setPackageName(anyString());
340         verify(buttonsController).show();
341     }
342
343     @Test
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);
362
363         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
364                 (InstantAppDataProvider) (i -> false));
365         mAppDetail.prepareInstantAppPrefs();
366
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);
370
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));
374
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);
380     }
381 }