• 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.fuelgauge;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.mockito.Matchers.any;
21 import static org.mockito.Matchers.anyInt;
22 import static org.mockito.Matchers.anyString;
23 import static org.mockito.Matchers.eq;
24 import static org.mockito.Mockito.doAnswer;
25 import static org.mockito.Mockito.doNothing;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.doThrow;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.never;
30 import static org.mockito.Mockito.spy;
31 import static org.mockito.Mockito.verify;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.ActivityManager;
35 import android.app.Application;
36 import android.app.Fragment;
37 import android.app.admin.DevicePolicyManager;
38 import android.content.Context;
39 import android.content.Intent;
40 import android.content.pm.ApplicationInfo;
41 import android.content.pm.PackageInfo;
42 import android.content.pm.PackageManager;
43 import android.os.UserManager;
44 
45 import com.android.settings.R;
46 import com.android.settings.SettingsActivity;
47 import com.android.settings.testutils.FakeFeatureFactory;
48 import com.android.settings.widget.ActionButtonPreference;
49 import com.android.settings.widget.ActionButtonPreferenceTest;
50 import com.android.settingslib.applications.AppUtils;
51 import com.android.settingslib.applications.ApplicationsState;
52 import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
53 import com.android.settingslib.core.lifecycle.Lifecycle;
54 
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.junit.runner.RunWith;
58 import org.mockito.Answers;
59 import org.mockito.ArgumentCaptor;
60 import org.mockito.Mock;
61 import org.mockito.MockitoAnnotations;
62 import org.mockito.stubbing.Answer;
63 import org.robolectric.RobolectricTestRunner;
64 import org.robolectric.util.ReflectionHelpers;
65 
66 @RunWith(RobolectricTestRunner.class)
67 public class AppButtonsPreferenceControllerTest {
68 
69     private static final String PACKAGE_NAME = "com.android.settings";
70     private static final String RESOURCE_STRING = "string";
71     private static final boolean ALL_USERS = false;
72     private static final boolean DISABLE_AFTER_INSTALL = true;
73     private static final int REQUEST_UNINSTALL = 0;
74     private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1;
75     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
76     private SettingsActivity mSettingsActivity;
77     @Mock
78     private TestFragment mFragment;
79     @Mock
80     private Lifecycle mLifecycle;
81     @Mock
82     private ApplicationsState mState;
83     @Mock
84     private ApplicationsState.AppEntry mAppEntry;
85     @Mock
86     private ApplicationInfo mAppInfo;
87     @Mock
88     private PackageManager mPackageManger;
89     @Mock
90     private DevicePolicyManager mDpm;
91     @Mock
92     private ActivityManager mAm;
93     @Mock
94     private UserManager mUserManager;
95     @Mock
96     private Application mApplication;
97     @Mock
98     private PackageInfo mPackageInfo;
99 
100     private ActionButtonPreference mButtonPrefs;
101 
102     private Intent mUninstallIntent;
103     private AppButtonsPreferenceController mController;
104 
105     @Before
setUp()106     public void setUp() {
107         MockitoAnnotations.initMocks(this);
108 
109         FakeFeatureFactory.setupForTest();
110         doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE);
111         doReturn(mPackageManger).when(mSettingsActivity).getPackageManager();
112         doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE);
113         doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt());
114         when(mSettingsActivity.getApplication()).thenReturn(mApplication);
115         when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(RESOURCE_STRING);
116 
117         mController = spy(new AppButtonsPreferenceController(mSettingsActivity, mFragment,
118                 mLifecycle, PACKAGE_NAME, mState, mDpm, mUserManager, mPackageManger,
119                 REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN));
120         doReturn(false).when(mController).isFallbackPackage(anyString());
121 
122         mAppEntry.info = mAppInfo;
123         mAppInfo.packageName = PACKAGE_NAME;
124         mAppInfo.flags = 0;
125         mPackageInfo.packageName = PACKAGE_NAME;
126         mPackageInfo.applicationInfo = mAppInfo;
127 
128         mButtonPrefs = ActionButtonPreferenceTest.createMock();
129         mController.mButtonsPref = mButtonPrefs;
130         mController.mPackageInfo = mPackageInfo;
131 
132         final ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
133         Answer<Void> callable = invocation -> {
134             mUninstallIntent = captor.getValue();
135             return null;
136         };
137         doAnswer(callable).when(mFragment).startActivityForResult(captor.capture(), anyInt());
138     }
139 
140     @Test
retrieveAppEntry_hasAppEntry_notNull()141     public void retrieveAppEntry_hasAppEntry_notNull()
142             throws PackageManager.NameNotFoundException {
143         doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
144 
145         mController.retrieveAppEntry();
146 
147         assertThat(mController.mAppEntry).isNotNull();
148         assertThat(mController.mPackageInfo).isNotNull();
149     }
150 
151     @Test
retrieveAppEntry_noAppEntry_null()152     public void retrieveAppEntry_noAppEntry_null() throws PackageManager.NameNotFoundException {
153         doReturn(null).when(mState).getEntry(eq(PACKAGE_NAME), anyInt());
154         doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt());
155 
156         mController.retrieveAppEntry();
157 
158         assertThat(mController.mAppEntry).isNull();
159         assertThat(mController.mPackageInfo).isNull();
160     }
161 
162     @Test
retrieveAppEntry_throwException_null()163     public void retrieveAppEntry_throwException_null() throws
164             PackageManager.NameNotFoundException {
165         doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt());
166         doThrow(new PackageManager.NameNotFoundException()).when(mPackageManger).getPackageInfo(
167                 anyString(), anyInt());
168 
169         mController.retrieveAppEntry();
170 
171         assertThat(mController.mAppEntry).isNotNull();
172         assertThat(mController.mPackageInfo).isNull();
173     }
174 
175     @Test
updateUninstallButton_isSystemApp_handleAsDisableableButton()176     public void updateUninstallButton_isSystemApp_handleAsDisableableButton() {
177         doReturn(false).when(mController).handleDisableable();
178         mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
179 
180         mController.updateUninstallButton();
181 
182         verify(mController).handleDisableable();
183         verify(mButtonPrefs).setButton1Enabled(false);
184     }
185 
186     @Test
isAvailable_nonInstantApp()187     public void isAvailable_nonInstantApp() throws Exception {
188         mController.mAppEntry = mAppEntry;
189         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
190                 new InstantAppDataProvider() {
191                     @Override
192                     public boolean isInstantApp(ApplicationInfo info) {
193                         return false;
194                     }
195                 });
196         assertThat(mController.isAvailable()).isTrue();
197     }
198 
199     @Test
isAvailable_instantApp()200     public void isAvailable_instantApp() throws Exception {
201         mController.mAppEntry = mAppEntry;
202         ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
203                 new InstantAppDataProvider() {
204                     @Override
205                     public boolean isInstantApp(ApplicationInfo info) {
206                         return true;
207                     }
208                 });
209         assertThat(mController.isAvailable()).isFalse();
210     }
211 
212     @Test
updateUninstallButton_isDeviceAdminApp_setButtonDisable()213     public void updateUninstallButton_isDeviceAdminApp_setButtonDisable() {
214         doReturn(true).when(mController).handleDisableable();
215         mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
216         doReturn(true).when(mDpm).packageHasActiveAdmins(anyString());
217 
218         mController.updateUninstallButton();
219 
220         verify(mController).handleDisableable();
221         verify(mButtonPrefs).setButton1Enabled(false);
222     }
223 
224     @Test
updateUninstallButton_isProfileOrDeviceOwner_setButtonDisable()225     public void updateUninstallButton_isProfileOrDeviceOwner_setButtonDisable() {
226         doReturn(true).when(mDpm).isDeviceOwnerAppOnAnyUser(anyString());
227 
228         mController.updateUninstallButton();
229 
230         verify(mButtonPrefs).setButton1Enabled(false);
231     }
232 
233     @Test
updateUninstallButton_isDeviceProvisioningApp_setButtonDisable()234     public void updateUninstallButton_isDeviceProvisioningApp_setButtonDisable() {
235         doReturn(true).when(mDpm).isDeviceOwnerAppOnAnyUser(anyString());
236         when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(PACKAGE_NAME);
237 
238         mController.updateUninstallButton();
239 
240         verify(mButtonPrefs).setButton1Enabled(false);
241     }
242 
243     @Test
updateUninstallButton_isUninstallInQueue_setButtonDisable()244     public void updateUninstallButton_isUninstallInQueue_setButtonDisable() {
245         doReturn(true).when(mDpm).isUninstallInQueue(any());
246 
247         mController.updateUninstallButton();
248 
249         verify(mButtonPrefs).setButton1Enabled(false);
250     }
251 
252     @Test
updateUninstallButton_isHomeAppAndBundled_setButtonDisable()253     public void updateUninstallButton_isHomeAppAndBundled_setButtonDisable() {
254         mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
255         mController.mHomePackages.add(PACKAGE_NAME);
256 
257         mController.updateUninstallButton();
258 
259         verify(mButtonPrefs).setButton1Enabled(false);
260     }
261 
262     @Test
updateForceStopButton_HasActiveAdmins_setButtonDisable()263     public void updateForceStopButton_HasActiveAdmins_setButtonDisable() {
264         doReturn(true).when(mDpm).packageHasActiveAdmins(anyString());
265 
266         mController.updateForceStopButton();
267 
268         verify(mController).updateForceStopButtonInner(false);
269     }
270 
271     @Test
updateForceStopButton_AppNotStopped_setButtonEnable()272     public void updateForceStopButton_AppNotStopped_setButtonEnable() {
273         mController.updateForceStopButton();
274 
275         verify(mController).updateForceStopButtonInner(true);
276     }
277 
278     @Test
uninstallPkg_intentSent()279     public void uninstallPkg_intentSent() {
280         mController.uninstallPkg(PACKAGE_NAME, ALL_USERS, DISABLE_AFTER_INSTALL);
281 
282         verify(mFragment).startActivityForResult(any(), eq(REQUEST_UNINSTALL));
283         assertThat(
284                 mUninstallIntent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, true))
285                 .isEqualTo(ALL_USERS);
286         assertThat(mUninstallIntent.getAction()).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE);
287         assertThat(mController.mDisableAfterUninstall).isEqualTo(DISABLE_AFTER_INSTALL);
288     }
289 
290     @Test
forceStopPackage_methodInvokedAndUpdated()291     public void forceStopPackage_methodInvokedAndUpdated() {
292         final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
293         doReturn(appEntry).when(mState).getEntry(anyString(), anyInt());
294         doNothing().when(mController).updateForceStopButton();
295 
296         mController.forceStopPackage(PACKAGE_NAME);
297 
298         verify(mAm).forceStopPackage(PACKAGE_NAME);
299         assertThat(mController.mAppEntry).isSameAs(appEntry);
300         verify(mController).updateForceStopButton();
301     }
302 
303     @Test
handleDisableable_isHomeApp_notControllable()304     public void handleDisableable_isHomeApp_notControllable() {
305         mController.mHomePackages.add(PACKAGE_NAME);
306 
307         final boolean controllable = mController.handleDisableable();
308 
309         verify(mButtonPrefs).setButton1Text(R.string.disable_text);
310         assertThat(controllable).isFalse();
311     }
312 
313     @Test
handleDisableable_isAppEnabled_controllable()314     public void handleDisableable_isAppEnabled_controllable() {
315         mAppEntry.info.enabled = true;
316         mAppEntry.info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
317         doReturn(false).when(mController).isSystemPackage(any(), any(), any());
318 
319         final boolean controllable = mController.handleDisableable();
320 
321         verify(mButtonPrefs).setButton1Text(R.string.disable_text);
322         assertThat(controllable).isTrue();
323     }
324 
325     @Test
handleDisableable_isAppDisabled_controllable()326     public void handleDisableable_isAppDisabled_controllable() {
327         mAppEntry.info.enabled = false;
328         mAppEntry.info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
329         doReturn(false).when(mController).isSystemPackage(any(), any(), any());
330 
331         final boolean controllable = mController.handleDisableable();
332 
333         verify(mButtonPrefs).setButton1Text(R.string.enable_text);
334         assertThat(controllable).isTrue();
335     }
336 
337     @Test
refreshUi_packageNull_shouldNotCrash()338     public void refreshUi_packageNull_shouldNotCrash() {
339         mController.mPackageName = null;
340 
341         // Should not crash in this method
342         assertThat(mController.refreshUi()).isFalse();
343     }
344 
345     @Test
onPackageListChanged_available_shouldRefreshUi()346     public void onPackageListChanged_available_shouldRefreshUi() {
347         doReturn(true).when(mController).isAvailable();
348         doReturn(true).when(mController).refreshUi();
349 
350         mController.onPackageListChanged();
351 
352         verify(mController).refreshUi();
353     }
354 
355     @Test
onPackageListChanged_notAvailable_shouldNotRefreshUiAndNoCrash()356     public void onPackageListChanged_notAvailable_shouldNotRefreshUiAndNoCrash() {
357         doReturn(false).when(mController).isAvailable();
358 
359         mController.onPackageListChanged();
360 
361         verify(mController, never()).refreshUi();
362         // Should not crash in this method
363     }
364 
365     /**
366      * The test fragment which implements
367      * {@link ButtonActionDialogFragment.AppButtonsDialogListener}
368      */
369     public static class TestFragment extends Fragment
370             implements ButtonActionDialogFragment.AppButtonsDialogListener {
371 
372         @Override
handleDialogClick(int type)373         public void handleDialogClick(int type) {
374             // Do nothing
375         }
376     }
377 }
378