1 /* 2 * Copyright (C) 2022 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.localepicker; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.mock; 22 import static org.mockito.Mockito.spy; 23 import static org.mockito.Mockito.times; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.app.Activity; 28 import android.app.ApplicationPackageManager; 29 import android.app.LocaleConfig; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.pm.ApplicationInfo; 33 import android.content.pm.InstallSourceInfo; 34 import android.content.pm.PackageInfo; 35 import android.content.pm.ResolveInfo; 36 import android.content.res.Resources; 37 import android.net.Uri; 38 import android.os.LocaleList; 39 import android.os.Process; 40 import android.os.UserHandle; 41 import android.telephony.TelephonyManager; 42 43 import androidx.annotation.ArrayRes; 44 45 import com.android.internal.app.LocaleStore; 46 import com.android.settings.applications.AppInfoBase; 47 import com.android.settings.applications.AppLocaleUtil; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Rule; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 import org.mockito.Mock; 55 import org.mockito.junit.MockitoJUnit; 56 import org.mockito.junit.MockitoRule; 57 import org.robolectric.Robolectric; 58 import org.robolectric.RobolectricTestRunner; 59 import org.robolectric.RuntimeEnvironment; 60 import org.robolectric.Shadows; 61 import org.robolectric.android.controller.ActivityController; 62 import org.robolectric.annotation.Config; 63 import org.robolectric.annotation.Implementation; 64 import org.robolectric.annotation.Implements; 65 import org.robolectric.shadows.ShadowPackageManager; 66 import org.robolectric.shadows.ShadowTelephonyManager; 67 import org.robolectric.util.ReflectionHelpers; 68 69 import java.util.ArrayList; 70 import java.util.List; 71 import java.util.Locale; 72 73 @RunWith(RobolectricTestRunner.class) 74 @Config( 75 shadows = { 76 AppLocalePickerActivityTest.ShadowApplicationPackageManager.class, 77 AppLocalePickerActivityTest.ShadowResources.class, 78 }) 79 public class AppLocalePickerActivityTest { 80 private static final String TEST_PACKAGE_NAME = "com.android.settings"; 81 private static final Uri TEST_PACKAGE_URI = Uri.parse("package:" + TEST_PACKAGE_NAME); 82 83 @Mock 84 LocaleStore.LocaleInfo mLocaleInfo; 85 @Mock 86 private LocaleConfig mLocaleConfig; 87 88 @Rule 89 public MockitoRule rule = MockitoJUnit.rule(); 90 91 private Context mContext; 92 private ShadowPackageManager mPackageManager; 93 94 @Before setUp()95 public void setUp() { 96 mContext = spy(RuntimeEnvironment.application); 97 mPackageManager = Shadows.shadowOf(mContext.getPackageManager()); 98 mLocaleConfig = mock(LocaleConfig.class); 99 when(mLocaleConfig.getStatus()).thenReturn(LocaleConfig.STATUS_SUCCESS); 100 when(mLocaleConfig.getSupportedLocales()).thenReturn(LocaleList.forLanguageTags("en-US")); 101 ReflectionHelpers.setStaticField(AppLocaleUtil.class, "sLocaleConfig", mLocaleConfig); 102 } 103 104 @After tearDown()105 public void tearDown() { 106 mPackageManager.removePackage(TEST_PACKAGE_NAME); 107 ReflectionHelpers.setStaticField(AppLocaleUtil.class, "sLocaleConfig", null); 108 ShadowResources.setDisAllowPackage(false); 109 ShadowApplicationPackageManager.setNoLaunchEntry(false); 110 } 111 112 @Test launchAppLocalePickerActivity_hasPackageName_success()113 public void launchAppLocalePickerActivity_hasPackageName_success() { 114 ActivityController<TestAppLocalePickerActivity> controller = 115 initActivityController(true); 116 controller.create(); 117 118 assertThat(controller.get().isFinishing()).isFalse(); 119 } 120 121 @Test launchAppLocalePickerActivity_appNoLocaleConfig_failed()122 public void launchAppLocalePickerActivity_appNoLocaleConfig_failed() { 123 when(mLocaleConfig.getStatus()).thenReturn(LocaleConfig.STATUS_NOT_SPECIFIED); 124 125 ActivityController<TestAppLocalePickerActivity> controller = 126 initActivityController(true); 127 controller.create(); 128 129 assertThat(controller.get().isFinishing()).isTrue(); 130 } 131 132 @Test launchAppLocalePickerActivity_appSignPlatformKey_failed()133 public void launchAppLocalePickerActivity_appSignPlatformKey_failed() { 134 final ApplicationInfo applicationInfo = new ApplicationInfo(); 135 applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY; 136 applicationInfo.packageName = TEST_PACKAGE_NAME; 137 138 final PackageInfo packageInfo = new PackageInfo(); 139 packageInfo.packageName = TEST_PACKAGE_NAME; 140 packageInfo.applicationInfo = applicationInfo; 141 mPackageManager.installPackage(packageInfo); 142 143 ActivityController<TestAppLocalePickerActivity> controller = 144 initActivityController(true); 145 controller.create(); 146 147 assertThat(controller.get().isFinishing()).isTrue(); 148 } 149 150 @Test launchAppLocalePickerActivity_appMatchDisallowedPackage_failed()151 public void launchAppLocalePickerActivity_appMatchDisallowedPackage_failed() { 152 ShadowResources.setDisAllowPackage(true); 153 154 ActivityController<TestAppLocalePickerActivity> controller = 155 initActivityController(true); 156 controller.create(); 157 158 assertThat(controller.get().isFinishing()).isTrue(); 159 } 160 161 @Test launchAppLocalePickerActivity_appNoLaunchEntry_failed()162 public void launchAppLocalePickerActivity_appNoLaunchEntry_failed() { 163 ShadowApplicationPackageManager.setNoLaunchEntry(true); 164 165 ActivityController<TestAppLocalePickerActivity> controller = 166 initActivityController(true); 167 controller.create(); 168 169 assertThat(controller.get().isFinishing()).isTrue(); 170 } 171 172 @Test launchAppLocalePickerActivity_intentWithoutPackageName_failed()173 public void launchAppLocalePickerActivity_intentWithoutPackageName_failed() { 174 ActivityController<TestAppLocalePickerActivity> controller = 175 initActivityController(false); 176 controller.create(); 177 178 assertThat(controller.get().isFinishing()).isTrue(); 179 } 180 181 @Test onLocaleSelected_getLocaleNotNull_getLanguageTag()182 public void onLocaleSelected_getLocaleNotNull_getLanguageTag() { 183 ActivityController<TestAppLocalePickerActivity> controller = 184 initActivityController(true); 185 Locale locale = new Locale("en", "US"); 186 when(mLocaleInfo.getLocale()).thenReturn(locale); 187 when(mLocaleInfo.isSystemLocale()).thenReturn(false); 188 189 controller.create(); 190 AppLocalePickerActivity mActivity = controller.get(); 191 mActivity.onLocaleSelected(mLocaleInfo); 192 193 verify(mLocaleInfo, times(2)).getLocale(); 194 assertThat(mLocaleInfo.getLocale().toLanguageTag()).isEqualTo("en-US"); 195 assertThat(controller.get().isFinishing()).isTrue(); 196 } 197 198 @Test onLocaleSelected_getLocaleNull_getEmptyLanguageTag()199 public void onLocaleSelected_getLocaleNull_getEmptyLanguageTag() { 200 ActivityController<TestAppLocalePickerActivity> controller = 201 initActivityController(true); 202 when(mLocaleInfo.getLocale()).thenReturn(null); 203 when(mLocaleInfo.isSystemLocale()).thenReturn(false); 204 205 controller.create(); 206 AppLocalePickerActivity mActivity = controller.get(); 207 mActivity.onLocaleSelected(mLocaleInfo); 208 209 verify(mLocaleInfo, times(1)).getLocale(); 210 assertThat(controller.get().isFinishing()).isTrue(); 211 } 212 initActivityController( boolean hasPackageName)213 private ActivityController<TestAppLocalePickerActivity> initActivityController( 214 boolean hasPackageName) { 215 Intent data = new Intent(); 216 if (hasPackageName) { 217 data.setData(TEST_PACKAGE_URI); 218 } 219 data.putExtra(AppInfoBase.ARG_PACKAGE_UID, Process.myUid()); 220 ActivityController<TestAppLocalePickerActivity> activityController = 221 Robolectric.buildActivity(TestAppLocalePickerActivity.class, data); 222 Activity activity = activityController.get(); 223 224 ShadowTelephonyManager shadowTelephonyManager = Shadows.shadowOf( 225 activity.getSystemService(TelephonyManager.class)); 226 shadowTelephonyManager.setSimCountryIso("US"); 227 shadowTelephonyManager.setNetworkCountryIso("US"); 228 229 return activityController; 230 } 231 232 private static class TestAppLocalePickerActivity extends AppLocalePickerActivity { 233 @Override createContextAsUser(UserHandle user, int flags)234 public Context createContextAsUser(UserHandle user, int flags) { 235 // return the current context as a work profile 236 return this; 237 } 238 } 239 240 @Implements(ApplicationPackageManager.class) 241 public static class ShadowApplicationPackageManager extends 242 org.robolectric.shadows.ShadowApplicationPackageManager { 243 private static boolean sNoLaunchEntry = false; 244 245 @Implementation getInstallSourceInfo(String packageName)246 protected Object getInstallSourceInfo(String packageName) { 247 return new InstallSourceInfo("", null, null, ""); 248 } 249 250 @Implementation queryIntentActivities(Intent intent, int flags)251 protected List<ResolveInfo> queryIntentActivities(Intent intent, int flags) { 252 if (sNoLaunchEntry) { 253 return new ArrayList(); 254 } else { 255 return super.queryIntentActivities(intent, flags); 256 } 257 } 258 setNoLaunchEntry(boolean noLaunchEntry)259 private static void setNoLaunchEntry(boolean noLaunchEntry) { 260 sNoLaunchEntry = noLaunchEntry; 261 } 262 } 263 264 @Implements(Resources.class) 265 public static class ShadowResources extends 266 org.robolectric.shadows.ShadowResources { 267 private static boolean sDisAllowPackage = false; 268 269 @Implementation getStringArray(@rrayRes int id)270 public String[] getStringArray(@ArrayRes int id) { 271 if (sDisAllowPackage) { 272 return new String[]{TEST_PACKAGE_NAME}; 273 } else { 274 return new String[0]; 275 } 276 } 277 setDisAllowPackage(boolean disAllowPackage)278 private static void setDisAllowPackage(boolean disAllowPackage) { 279 sDisAllowPackage = disAllowPackage; 280 } 281 } 282 } 283