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