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.appinfo; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.argThat; 23 import static org.mockito.ArgumentMatchers.eq; 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.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.content.ComponentName; 31 import android.content.Context; 32 import android.content.DialogInterface; 33 import android.content.Intent; 34 import android.content.pm.ActivityInfo; 35 import android.content.pm.ApplicationInfo; 36 import android.content.pm.PackageInfo; 37 import android.content.pm.PackageManager; 38 import android.content.pm.ResolveInfo; 39 import android.support.v7.preference.PreferenceManager; 40 import android.support.v7.preference.PreferenceScreen; 41 import android.text.TextUtils; 42 import android.view.Menu; 43 import android.view.MenuItem; 44 import android.view.View; 45 import android.widget.Button; 46 47 import com.android.settings.R; 48 import com.android.settings.applications.LayoutPreference; 49 import com.android.settings.core.BasePreferenceController; 50 import com.android.settings.testutils.SettingsRobolectricTestRunner; 51 import com.android.settingslib.applications.AppUtils; 52 import com.android.settingslib.applications.instantapps.InstantAppDataProvider; 53 import com.android.settingslib.wrapper.PackageManagerWrapper; 54 55 import org.junit.Before; 56 import org.junit.Test; 57 import org.junit.runner.RunWith; 58 import org.mockito.Mock; 59 import org.mockito.MockitoAnnotations; 60 import org.robolectric.RuntimeEnvironment; 61 import org.robolectric.util.ReflectionHelpers; 62 63 @RunWith(SettingsRobolectricTestRunner.class) 64 public class InstantAppButtonsPreferenceControllerTest { 65 66 private static final String TEST_INSTALLER_PACKAGE_NAME = "com.installer"; 67 private static final String TEST_INSTALLER_ACTIVITY_NAME = "com.installer.InstallerActivity"; 68 private static final String TEST_AIA_PACKAGE_NAME = "test.aia.package"; 69 70 @Mock 71 private PackageManager mPackageManager; 72 @Mock 73 private ApplicationInfo mAppInfo; 74 @Mock 75 private AppInfoDashboardFragment mFragment; 76 @Mock 77 private LayoutPreference mPreference; 78 79 private Context mContext; 80 private PreferenceScreen mScreen; 81 private PreferenceManager mPreferenceManager; 82 private Button mLaunchButton; 83 private Button mInstallButton; 84 private Button mClearAppButton; 85 private InstantAppButtonsPreferenceController mController; 86 87 @Before 88 public void setUp() throws PackageManager.NameNotFoundException { 89 MockitoAnnotations.initMocks(this); 90 mContext = spy(RuntimeEnvironment.application); 91 when(mContext.getPackageManager()).thenReturn(mPackageManager); 92 final PackageInfo packageInfo = mock(PackageInfo.class); 93 packageInfo.applicationInfo = mAppInfo; 94 when(mFragment.getPackageInfo()).thenReturn(packageInfo); 95 mPreferenceManager = new PreferenceManager(mContext); 96 mScreen = mPreferenceManager.createPreferenceScreen(mContext); 97 when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager); 98 final View buttons = View.inflate( 99 RuntimeEnvironment.application, R.layout.instant_app_buttons, null /* parent */); 100 mLaunchButton = buttons.findViewById(R.id.launch); 101 mInstallButton = buttons.findViewById(R.id.install); 102 mClearAppButton = buttons.findViewById(R.id.clear_data); 103 mController = spy(new InstantAppButtonsPreferenceController( 104 mContext, mFragment, TEST_AIA_PACKAGE_NAME, null /* lifecycle */)); 105 when(mPreference.getKey()).thenReturn("instant_app_buttons"); 106 mScreen.addPreference(mPreference); 107 when(mPreference.findViewById(R.id.instant_app_button_container)).thenReturn(buttons); 108 } 109 110 @Test 111 public void getAvailabilityStatus_notInstantApp_shouldReturnDisabled() { 112 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", 113 (InstantAppDataProvider) (i -> false)); 114 115 assertThat(mController.getAvailabilityStatus()) 116 .isEqualTo(BasePreferenceController.DISABLED_FOR_USER); 117 } 118 119 @Test 120 public void getAvailabilityStatus_isInstantApp_shouldReturnAvailable() { 121 ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider", 122 (InstantAppDataProvider) (i -> true)); 123 124 assertThat(mController.getAvailabilityStatus()) 125 .isEqualTo(BasePreferenceController.AVAILABLE); 126 } 127 128 @Test 129 public void onCreateOptionsMenu_noLaunchUri_shouldNotAddInstallInstantAppMenu() { 130 final Menu menu = mock(Menu.class); 131 when(menu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mock(MenuItem.class)); 132 133 mController.onCreateOptionsMenu(menu, null /* inflater */); 134 135 verify(menu, never()).add(anyInt(), eq(AppInfoDashboardFragment.INSTALL_INSTANT_APP_MENU), 136 anyInt(), eq(R.string.install_text)); 137 } 138 139 @Test 140 public void onCreateOptionsMenu_hasLaunchUri_shouldAddForceStop() { 141 ReflectionHelpers.setField(mController, "mLaunchUri", "www.test.launch"); 142 final Menu menu = mock(Menu.class); 143 when(menu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mock(MenuItem.class)); 144 145 mController.onCreateOptionsMenu(menu, null /* inflater */); 146 147 verify(menu).add(anyInt(), eq(AppInfoDashboardFragment.INSTALL_INSTANT_APP_MENU), 148 anyInt(), eq(R.string.install_text)); 149 } 150 151 @Test 152 public void onPrepareOptionsMenu_noAppStoreLink_shoulDisableInstallInstantAppMenu() { 153 ReflectionHelpers.setField(mController, "mLaunchUri", "www.test.launch"); 154 final Menu menu = mock(Menu.class); 155 final MenuItem menuItem = mock(MenuItem.class); 156 when(menu.findItem(AppInfoDashboardFragment.INSTALL_INSTANT_APP_MENU)).thenReturn(menuItem); 157 158 mController.onPrepareOptionsMenu(menu); 159 160 verify(menuItem).setEnabled(false); 161 } 162 163 @Test 164 public void onPrepareOptionsMenu_hasAppStoreLink_shoulNotDisableInstallInstantAppMenu() { 165 ReflectionHelpers.setField(mController, "mLaunchUri", "www.test.launch"); 166 final ResolveInfo resolveInfo = mock(ResolveInfo.class); 167 final ActivityInfo activityInfo = mock(ActivityInfo.class); 168 resolveInfo.activityInfo = activityInfo; 169 activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME; 170 activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME; 171 when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo); 172 final Menu menu = mock(Menu.class); 173 final MenuItem menuItem = mock(MenuItem.class); 174 when(menu.findItem(AppInfoDashboardFragment.INSTALL_INSTANT_APP_MENU)).thenReturn(menuItem); 175 176 mController.onPrepareOptionsMenu(menu); 177 178 verify(menuItem, never()).setEnabled(false); 179 } 180 181 @Test 182 public void onPrepareOptionsMenu_installMenuNotFound_shoulNotCrash() { 183 final Menu menu = mock(Menu.class); 184 185 mController.onPrepareOptionsMenu(menu); 186 187 // no crash 188 } 189 190 @Test 191 public void onOptionsItemSelected_shouldOpenAppStore() { 192 final ResolveInfo resolveInfo = mock(ResolveInfo.class); 193 final ActivityInfo activityInfo = mock(ActivityInfo.class); 194 resolveInfo.activityInfo = activityInfo; 195 activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME; 196 activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME; 197 when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo); 198 mController.displayPreference(mScreen); 199 final ComponentName componentName = 200 new ComponentName(TEST_INSTALLER_PACKAGE_NAME, TEST_INSTALLER_ACTIVITY_NAME); 201 final MenuItem menu = mock(MenuItem.class); 202 when(menu.getItemId()).thenReturn(AppInfoDashboardFragment.INSTALL_INSTANT_APP_MENU); 203 204 mController.onOptionsItemSelected(menu); 205 206 verify(mFragment).startActivity(argThat(intent-> intent != null 207 && intent.getAction().equals(Intent.ACTION_SHOW_APP_INFO) 208 && intent.getComponent().equals(componentName))); 209 } 210 211 @Test 212 public void displayPreference_noLaunchUri_shouldShowHideLaunchButton() { 213 mController.displayPreference(mScreen); 214 215 assertThat(mLaunchButton.getVisibility()).isEqualTo(View.GONE); 216 } 217 218 @Test 219 public void displayPreference_hasLaunchUri_shouldShowHideInstallButton() { 220 ReflectionHelpers.setField(mController, "mLaunchUri", "www.test.launch"); 221 222 mController.displayPreference(mScreen); 223 224 assertThat(mInstallButton.getVisibility()).isEqualTo(View.GONE); 225 } 226 227 @Test 228 public void displayPreference_noAppStoreLink_shoulDisableInstallButton() { 229 mController.displayPreference(mScreen); 230 231 assertThat(mInstallButton.isEnabled()).isFalse(); 232 } 233 234 @Test 235 public void displayPreference_hasAppStoreLink_shoulSetClickListenerForInstallButton() { 236 final ResolveInfo resolveInfo = mock(ResolveInfo.class); 237 final ActivityInfo activityInfo = mock(ActivityInfo.class); 238 resolveInfo.activityInfo = activityInfo; 239 activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME; 240 activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME; 241 when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo); 242 243 mController.displayPreference(mScreen); 244 245 assertThat(mInstallButton.hasOnClickListeners()).isTrue(); 246 } 247 248 @Test 249 public void displayPreference_shoulSetClickListenerForClearButton() { 250 mController.displayPreference(mScreen); 251 252 assertThat(mClearAppButton.hasOnClickListeners()).isTrue(); 253 } 254 255 @Test 256 public void clickLaunchButton_shouldLaunchViewIntent() { 257 final String launchUri = "www.test.launch"; 258 ReflectionHelpers.setField(mController, "mLaunchUri", launchUri); 259 mController.displayPreference(mScreen); 260 261 mLaunchButton.callOnClick(); 262 263 verify(mFragment).startActivity(argThat(intent-> intent != null 264 && intent.getAction().equals(Intent.ACTION_VIEW) 265 && intent.hasCategory(Intent.CATEGORY_BROWSABLE) 266 && (intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 267 && TextUtils.equals(intent.getPackage(), TEST_AIA_PACKAGE_NAME) 268 && TextUtils.equals(intent.getDataString(), launchUri))); 269 } 270 271 @Test 272 public void clickInstallButton_shouldOpenAppStore() { 273 final ResolveInfo resolveInfo = mock(ResolveInfo.class); 274 final ActivityInfo activityInfo = mock(ActivityInfo.class); 275 resolveInfo.activityInfo = activityInfo; 276 activityInfo.packageName = TEST_INSTALLER_PACKAGE_NAME; 277 activityInfo.name = TEST_INSTALLER_ACTIVITY_NAME; 278 when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo); 279 mController.displayPreference(mScreen); 280 final ComponentName componentName = 281 new ComponentName(TEST_INSTALLER_PACKAGE_NAME, TEST_INSTALLER_ACTIVITY_NAME); 282 283 mInstallButton.callOnClick(); 284 285 verify(mFragment).startActivity(argThat(intent-> intent != null 286 && intent.getAction().equals(Intent.ACTION_SHOW_APP_INFO) 287 && intent.getComponent().equals(componentName))); 288 } 289 290 @Test 291 public void onClick_shouldDeleteApp() { 292 PackageManagerWrapper packageManagerWrapper = mock(PackageManagerWrapper.class); 293 ReflectionHelpers.setField(mController, "mPackageManagerWrapper", packageManagerWrapper); 294 295 mController.onClick(mock(DialogInterface.class), DialogInterface.BUTTON_POSITIVE); 296 297 verify(packageManagerWrapper) 298 .deletePackageAsUser(eq(TEST_AIA_PACKAGE_NAME), any(), anyInt(),anyInt()); 299 } 300 } 301