/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.Application; import android.app.Fragment; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.UserManager; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.widget.ActionButtonPreference; import com.android.settings.widget.ActionButtonPreferenceTest; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.instantapps.InstantAppDataProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; import org.robolectric.util.ReflectionHelpers; @RunWith(RobolectricTestRunner.class) public class AppButtonsPreferenceControllerTest { private static final String PACKAGE_NAME = "com.android.settings"; private static final String RESOURCE_STRING = "string"; private static final boolean ALL_USERS = false; private static final boolean DISABLE_AFTER_INSTALL = true; private static final int REQUEST_UNINSTALL = 0; private static final int REQUEST_REMOVE_DEVICE_ADMIN = 1; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private SettingsActivity mSettingsActivity; @Mock private TestFragment mFragment; @Mock private Lifecycle mLifecycle; @Mock private ApplicationsState mState; @Mock private ApplicationsState.AppEntry mAppEntry; @Mock private ApplicationInfo mAppInfo; @Mock private PackageManager mPackageManger; @Mock private DevicePolicyManager mDpm; @Mock private ActivityManager mAm; @Mock private UserManager mUserManager; @Mock private Application mApplication; @Mock private PackageInfo mPackageInfo; private ActionButtonPreference mButtonPrefs; private Intent mUninstallIntent; private AppButtonsPreferenceController mController; @Before public void setUp() { MockitoAnnotations.initMocks(this); FakeFeatureFactory.setupForTest(); doReturn(mUserManager).when(mSettingsActivity).getSystemService(Context.USER_SERVICE); doReturn(mPackageManger).when(mSettingsActivity).getPackageManager(); doReturn(mAm).when(mSettingsActivity).getSystemService(Context.ACTIVITY_SERVICE); doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt()); when(mSettingsActivity.getApplication()).thenReturn(mApplication); when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(RESOURCE_STRING); mController = spy(new AppButtonsPreferenceController(mSettingsActivity, mFragment, mLifecycle, PACKAGE_NAME, mState, mDpm, mUserManager, mPackageManger, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN)); doReturn(false).when(mController).isFallbackPackage(anyString()); mAppEntry.info = mAppInfo; mAppInfo.packageName = PACKAGE_NAME; mAppInfo.flags = 0; mPackageInfo.packageName = PACKAGE_NAME; mPackageInfo.applicationInfo = mAppInfo; mButtonPrefs = ActionButtonPreferenceTest.createMock(); mController.mButtonsPref = mButtonPrefs; mController.mPackageInfo = mPackageInfo; final ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); Answer callable = invocation -> { mUninstallIntent = captor.getValue(); return null; }; doAnswer(callable).when(mFragment).startActivityForResult(captor.capture(), anyInt()); } @Test public void retrieveAppEntry_hasAppEntry_notNull() throws PackageManager.NameNotFoundException { doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt()); mController.retrieveAppEntry(); assertThat(mController.mAppEntry).isNotNull(); assertThat(mController.mPackageInfo).isNotNull(); } @Test public void retrieveAppEntry_noAppEntry_null() throws PackageManager.NameNotFoundException { doReturn(null).when(mState).getEntry(eq(PACKAGE_NAME), anyInt()); doReturn(mPackageInfo).when(mPackageManger).getPackageInfo(anyString(), anyInt()); mController.retrieveAppEntry(); assertThat(mController.mAppEntry).isNull(); assertThat(mController.mPackageInfo).isNull(); } @Test public void retrieveAppEntry_throwException_null() throws PackageManager.NameNotFoundException { doReturn(mAppEntry).when(mState).getEntry(anyString(), anyInt()); doThrow(new PackageManager.NameNotFoundException()).when(mPackageManger).getPackageInfo( anyString(), anyInt()); mController.retrieveAppEntry(); assertThat(mController.mAppEntry).isNotNull(); assertThat(mController.mPackageInfo).isNull(); } @Test public void updateUninstallButton_isSystemApp_handleAsDisableableButton() { doReturn(false).when(mController).handleDisableable(); mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM; mController.updateUninstallButton(); verify(mController).handleDisableable(); verify(mButtonPrefs).setButton1Enabled(false); } @Test public void isAvailable_nonInstantApp() throws Exception { mController.mAppEntry = mAppEntry; ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", new InstantAppDataProvider() { @Override public boolean isInstantApp(ApplicationInfo info) { return false; } }); assertThat(mController.isAvailable()).isTrue(); } @Test public void isAvailable_instantApp() throws Exception { mController.mAppEntry = mAppEntry; ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", new InstantAppDataProvider() { @Override public boolean isInstantApp(ApplicationInfo info) { return true; } }); assertThat(mController.isAvailable()).isFalse(); } @Test public void updateUninstallButton_isDeviceAdminApp_setButtonDisable() { doReturn(true).when(mController).handleDisableable(); mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM; doReturn(true).when(mDpm).packageHasActiveAdmins(anyString()); mController.updateUninstallButton(); verify(mController).handleDisableable(); verify(mButtonPrefs).setButton1Enabled(false); } @Test public void updateUninstallButton_isProfileOrDeviceOwner_setButtonDisable() { doReturn(true).when(mDpm).isDeviceOwnerAppOnAnyUser(anyString()); mController.updateUninstallButton(); verify(mButtonPrefs).setButton1Enabled(false); } @Test public void updateUninstallButton_isDeviceProvisioningApp_setButtonDisable() { doReturn(true).when(mDpm).isDeviceOwnerAppOnAnyUser(anyString()); when(mSettingsActivity.getResources().getString(anyInt())).thenReturn(PACKAGE_NAME); mController.updateUninstallButton(); verify(mButtonPrefs).setButton1Enabled(false); } @Test public void updateUninstallButton_isUninstallInQueue_setButtonDisable() { doReturn(true).when(mDpm).isUninstallInQueue(any()); mController.updateUninstallButton(); verify(mButtonPrefs).setButton1Enabled(false); } @Test public void updateUninstallButton_isHomeAppAndBundled_setButtonDisable() { mAppInfo.flags |= ApplicationInfo.FLAG_SYSTEM; mController.mHomePackages.add(PACKAGE_NAME); mController.updateUninstallButton(); verify(mButtonPrefs).setButton1Enabled(false); } @Test public void updateForceStopButton_HasActiveAdmins_setButtonDisable() { doReturn(true).when(mDpm).packageHasActiveAdmins(anyString()); mController.updateForceStopButton(); verify(mController).updateForceStopButtonInner(false); } @Test public void updateForceStopButton_AppNotStopped_setButtonEnable() { mController.updateForceStopButton(); verify(mController).updateForceStopButtonInner(true); } @Test public void uninstallPkg_intentSent() { mController.uninstallPkg(PACKAGE_NAME, ALL_USERS, DISABLE_AFTER_INSTALL); verify(mFragment).startActivityForResult(any(), eq(REQUEST_UNINSTALL)); assertThat( mUninstallIntent.getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, true)) .isEqualTo(ALL_USERS); assertThat(mUninstallIntent.getAction()).isEqualTo(Intent.ACTION_UNINSTALL_PACKAGE); assertThat(mController.mDisableAfterUninstall).isEqualTo(DISABLE_AFTER_INSTALL); } @Test public void forceStopPackage_methodInvokedAndUpdated() { final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class); doReturn(appEntry).when(mState).getEntry(anyString(), anyInt()); doNothing().when(mController).updateForceStopButton(); mController.forceStopPackage(PACKAGE_NAME); verify(mAm).forceStopPackage(PACKAGE_NAME); assertThat(mController.mAppEntry).isSameAs(appEntry); verify(mController).updateForceStopButton(); } @Test public void handleDisableable_isHomeApp_notControllable() { mController.mHomePackages.add(PACKAGE_NAME); final boolean controllable = mController.handleDisableable(); verify(mButtonPrefs).setButton1Text(R.string.disable_text); assertThat(controllable).isFalse(); } @Test public void handleDisableable_isAppEnabled_controllable() { mAppEntry.info.enabled = true; mAppEntry.info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; doReturn(false).when(mController).isSystemPackage(any(), any(), any()); final boolean controllable = mController.handleDisableable(); verify(mButtonPrefs).setButton1Text(R.string.disable_text); assertThat(controllable).isTrue(); } @Test public void handleDisableable_isAppDisabled_controllable() { mAppEntry.info.enabled = false; mAppEntry.info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; doReturn(false).when(mController).isSystemPackage(any(), any(), any()); final boolean controllable = mController.handleDisableable(); verify(mButtonPrefs).setButton1Text(R.string.enable_text); assertThat(controllable).isTrue(); } @Test public void refreshUi_packageNull_shouldNotCrash() { mController.mPackageName = null; // Should not crash in this method assertThat(mController.refreshUi()).isFalse(); } @Test public void onPackageListChanged_available_shouldRefreshUi() { doReturn(true).when(mController).isAvailable(); doReturn(true).when(mController).refreshUi(); mController.onPackageListChanged(); verify(mController).refreshUi(); } @Test public void onPackageListChanged_notAvailable_shouldNotRefreshUiAndNoCrash() { doReturn(false).when(mController).isAvailable(); mController.onPackageListChanged(); verify(mController, never()).refreshUi(); // Should not crash in this method } /** * The test fragment which implements * {@link ButtonActionDialogFragment.AppButtonsDialogListener} */ public static class TestFragment extends Fragment implements ButtonActionDialogFragment.AppButtonsDialogListener { @Override public void handleDialogClick(int type) { // Do nothing } } }