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.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.spy;
25 import static org.mockito.Mockito.times;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28 
29 import android.app.Activity;
30 import android.app.ApplicationPackageManager;
31 import android.app.LocaleConfig;
32 import android.app.settings.SettingsEnums;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.pm.ApplicationInfo;
36 import android.content.pm.InstallSourceInfo;
37 import android.content.pm.PackageInfo;
38 import android.content.pm.PackageManager.NameNotFoundException;
39 import android.content.pm.ResolveInfo;
40 import android.content.res.Resources;
41 import android.net.Uri;
42 import android.os.LocaleList;
43 import android.os.Process;
44 import android.os.SystemClock;
45 import android.os.UserHandle;
46 import android.platform.test.annotations.RequiresFlagsEnabled;
47 import android.platform.test.flag.junit.CheckFlagsRule;
48 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
49 import android.telephony.TelephonyManager;
50 
51 import androidx.annotation.ArrayRes;
52 
53 import com.android.internal.app.LocaleStore;
54 import com.android.settings.applications.AppInfoBase;
55 import com.android.settings.applications.AppLocaleUtil;
56 import com.android.settings.flags.Flags;
57 import com.android.settings.testutils.FakeFeatureFactory;
58 
59 import org.junit.After;
60 import org.junit.Before;
61 import org.junit.Rule;
62 import org.junit.Test;
63 import org.junit.runner.RunWith;
64 import org.mockito.Mock;
65 import org.mockito.junit.MockitoJUnit;
66 import org.mockito.junit.MockitoRule;
67 import org.robolectric.Robolectric;
68 import org.robolectric.RobolectricTestRunner;
69 import org.robolectric.RuntimeEnvironment;
70 import org.robolectric.Shadows;
71 import org.robolectric.android.controller.ActivityController;
72 import org.robolectric.annotation.Config;
73 import org.robolectric.annotation.Implementation;
74 import org.robolectric.annotation.Implements;
75 import org.robolectric.shadows.ShadowPackageManager;
76 import org.robolectric.shadows.ShadowTelephonyManager;
77 import org.robolectric.util.ReflectionHelpers;
78 
79 import java.util.ArrayList;
80 import java.util.Calendar;
81 import java.util.List;
82 import java.util.Locale;
83 import java.util.Set;
84 
85 @RunWith(RobolectricTestRunner.class)
86 @Config(
87         shadows = {
88                 AppLocalePickerActivityTest.ShadowApplicationPackageManager.class,
89                 AppLocalePickerActivityTest.ShadowResources.class,
90         })
91 public class AppLocalePickerActivityTest {
92     private static final String TEST_PACKAGE_NAME = "com.android.settings";
93     private static final Uri TEST_PACKAGE_URI = Uri.parse("package:" + TEST_PACKAGE_NAME);
94     private static final String EN_CA = "en-CA";
95     private static final String EN_US = "en-US";
96     private static int sUid;
97 
98     private FakeFeatureFactory mFeatureFactory;
99     private LocaleNotificationDataManager mDataManager;
100     private AppLocalePickerActivity mActivity;
101 
102     @Mock
103     LocaleStore.LocaleInfo mLocaleInfo;
104     @Mock
105     private LocaleConfig mLocaleConfig;
106 
107     @Rule
108     public MockitoRule rule = MockitoJUnit.rule();
109     @Rule
110     public final CheckFlagsRule mCheckFlagsRule =
111             DeviceFlagsValueProvider.createCheckFlagsRule();
112 
113     private Context mContext;
114     private ShadowPackageManager mPackageManager;
115 
116     @Before
setUp()117     public void setUp() {
118         mContext = spy(RuntimeEnvironment.application);
119         mPackageManager = Shadows.shadowOf(mContext.getPackageManager());
120         mLocaleConfig = mock(LocaleConfig.class);
121         when(mLocaleConfig.getStatus()).thenReturn(LocaleConfig.STATUS_SUCCESS);
122         when(mLocaleConfig.getSupportedLocales()).thenReturn(LocaleList.forLanguageTags("en-US"));
123         ReflectionHelpers.setStaticField(AppLocaleUtil.class, "sLocaleConfig", mLocaleConfig);
124         sUid = Process.myUid();
125         mFeatureFactory = FakeFeatureFactory.setupForTest();
126     }
127 
128     @After
tearDown()129     public void tearDown() throws Exception {
130         mPackageManager.removePackage(TEST_PACKAGE_NAME);
131         ReflectionHelpers.setStaticField(AppLocaleUtil.class, "sLocaleConfig", null);
132         ShadowResources.setDisAllowPackage(false);
133         ShadowApplicationPackageManager.setNoLaunchEntry(false);
134     }
135 
136     @Test
launchAppLocalePickerActivity_hasPackageName_success()137     public void launchAppLocalePickerActivity_hasPackageName_success() {
138         ActivityController<TestAppLocalePickerActivity> controller =
139                 initActivityController(true);
140         controller.create();
141 
142         assertThat(controller.get().isFinishing()).isFalse();
143     }
144 
145     @Test
launchAppLocalePickerActivity_appNoLocaleConfig_failed()146     public void launchAppLocalePickerActivity_appNoLocaleConfig_failed() {
147         when(mLocaleConfig.getStatus()).thenReturn(LocaleConfig.STATUS_NOT_SPECIFIED);
148 
149         ActivityController<TestAppLocalePickerActivity> controller =
150                 initActivityController(true);
151         controller.create();
152 
153         assertThat(controller.get().isFinishing()).isTrue();
154     }
155 
156     @Test
launchAppLocalePickerActivity_appSignPlatformKey_failed()157     public void launchAppLocalePickerActivity_appSignPlatformKey_failed() {
158         final ApplicationInfo applicationInfo = new ApplicationInfo();
159         applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
160         applicationInfo.packageName = TEST_PACKAGE_NAME;
161 
162         final PackageInfo packageInfo = new PackageInfo();
163         packageInfo.packageName = TEST_PACKAGE_NAME;
164         packageInfo.applicationInfo = applicationInfo;
165         mPackageManager.installPackage(packageInfo);
166 
167         ActivityController<TestAppLocalePickerActivity> controller =
168                 initActivityController(true);
169         controller.create();
170 
171         assertThat(controller.get().isFinishing()).isTrue();
172     }
173 
174     @Test
launchAppLocalePickerActivity_appMatchDisallowedPackage_failed()175     public void launchAppLocalePickerActivity_appMatchDisallowedPackage_failed() {
176         ShadowResources.setDisAllowPackage(true);
177 
178         ActivityController<TestAppLocalePickerActivity> controller =
179                 initActivityController(true);
180         controller.create();
181 
182         assertThat(controller.get().isFinishing()).isTrue();
183     }
184 
185     @Test
launchAppLocalePickerActivity_appNoLaunchEntry_failed()186     public void launchAppLocalePickerActivity_appNoLaunchEntry_failed() {
187         ShadowApplicationPackageManager.setNoLaunchEntry(true);
188 
189         ActivityController<TestAppLocalePickerActivity> controller =
190                 initActivityController(true);
191         controller.create();
192 
193         assertThat(controller.get().isFinishing()).isTrue();
194     }
195 
196     @Test
launchAppLocalePickerActivity_intentWithoutPackageName_failed()197     public void launchAppLocalePickerActivity_intentWithoutPackageName_failed() {
198         ActivityController<TestAppLocalePickerActivity> controller =
199                 initActivityController(false);
200         controller.create();
201 
202         assertThat(controller.get().isFinishing()).isTrue();
203     }
204 
205     @Test
onLocaleSelected_getLocaleNotNull_getLanguageTag()206     public void onLocaleSelected_getLocaleNotNull_getLanguageTag() {
207         ActivityController<TestAppLocalePickerActivity> controller =
208                 initActivityController(true);
209         Locale locale = new Locale("en", "US");
210         when(mLocaleInfo.getLocale()).thenReturn(locale);
211         when(mLocaleInfo.isSystemLocale()).thenReturn(false);
212 
213         controller.create();
214         AppLocalePickerActivity mActivity = controller.get();
215         mActivity.onLocaleSelected(mLocaleInfo);
216 
217         // 1st for getLocale()!= null
218         // 2nd for setAppDefaultLocale(getLocale())
219         // 3rd for broadcastAppLocaleChange()
220         verify(mLocaleInfo, times(3)).getLocale();
221         assertThat(mLocaleInfo.getLocale().toLanguageTag()).isEqualTo("en-US");
222         assertThat(controller.get().isFinishing()).isTrue();
223     }
224 
225     @Test
onLocaleSelected_getLocaleNull_getEmptyLanguageTag()226     public void onLocaleSelected_getLocaleNull_getEmptyLanguageTag() {
227         ActivityController<TestAppLocalePickerActivity> controller =
228                 initActivityController(true);
229         when(mLocaleInfo.getLocale()).thenReturn(null);
230         when(mLocaleInfo.isSystemLocale()).thenReturn(false);
231 
232         controller.create();
233         AppLocalePickerActivity mActivity = controller.get();
234         mActivity.onLocaleSelected(mLocaleInfo);
235 
236         verify(mLocaleInfo, times(1)).getLocale();
237         assertThat(controller.get().isFinishing()).isTrue();
238     }
239 
240     @Test
onLocaleSelected_logLocaleSource()241     public void onLocaleSelected_logLocaleSource() {
242         ActivityController<TestAppLocalePickerActivity> controller =
243                 initActivityController(true);
244         LocaleList.setDefault(LocaleList.forLanguageTags("ja-JP,en-CA,en-US"));
245         Locale locale = new Locale("en", "US");
246         when(mLocaleInfo.getLocale()).thenReturn(locale);
247         when(mLocaleInfo.isSystemLocale()).thenReturn(false);
248         when(mLocaleInfo.isSuggested()).thenReturn(true);
249         when(mLocaleInfo.isSuggestionOfType(LocaleStore.LocaleInfo.SUGGESTION_TYPE_SIM)).thenReturn(
250                 true);
251         when(mLocaleInfo.isSuggestionOfType(
252                 LocaleStore.LocaleInfo.SUGGESTION_TYPE_SYSTEM_AVAILABLE_LANGUAGE)).thenReturn(
253                 true);
254         when(mLocaleInfo.isSuggestionOfType(
255                 LocaleStore.LocaleInfo.SUGGESTION_TYPE_OTHER_APP_LANGUAGE)).thenReturn(
256                 true);
257         when(mLocaleInfo.isSuggestionOfType(
258                 LocaleStore.LocaleInfo.SUGGESTION_TYPE_IME_LANGUAGE)).thenReturn(
259                 true);
260 
261         controller.create();
262         AppLocalePickerActivity mActivity = controller.get();
263         mActivity.onLocaleSelected(mLocaleInfo);
264 
265         int localeSource = 15; // SIM_LOCALE | SYSTEM_LOCALE |IME_LOCALE|APP_LOCALE
266         verify(mFeatureFactory.metricsFeatureProvider).action(
267                 any(), eq(SettingsEnums.ACTION_CHANGE_APP_LANGUAGE_FROM_SUGGESTED),
268                 eq(localeSource));
269     }
270 
271     @Test
272     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
onLocaleSelected_evaluateNotification_simpleLocaleUpdate_localeCreatedWithUid()273     public void onLocaleSelected_evaluateNotification_simpleLocaleUpdate_localeCreatedWithUid()
274             throws Exception {
275         sUid = 100;
276         initLocaleNotificationEnvironment();
277         ActivityController<TestAppLocalePickerActivity> controller = initActivityController(true);
278         controller.create();
279         AppLocalePickerActivity mActivity = controller.get();
280         LocaleNotificationDataManager dataManager =
281                 NotificationController.getInstance(mActivity).getDataManager();
282 
283         mActivity.onLocaleSelected(mLocaleInfo);
284 
285         // Notification is not triggered.
286         // In the sharedpreference, en-US's uid list contains uid1 and the notificationCount
287         // equals 0.
288         NotificationInfo info = dataManager.getNotificationInfo(EN_US);
289         assertThat(info.getUidCollection().contains(sUid)).isTrue();
290         assertThat(info.getNotificationCount()).isEqualTo(0);
291         assertThat(info.getDismissCount()).isEqualTo(0);
292         assertThat(info.getLastNotificationTimeMs()).isEqualTo(0);
293 
294         mDataManager.clearLocaleNotificationMap();
295     }
296 
297     @Test
298     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
onLocaleSelected_evaluateNotification_twoLocaleUpdate_triggerNotification()299     public void onLocaleSelected_evaluateNotification_twoLocaleUpdate_triggerNotification()
300             throws Exception {
301         // App with uid 101 changed its locale from System to en-US.
302         sUid = 101;
303         initLocaleNotificationEnvironment();
304         // Initialize the proto to contain en-US locale. Its uid list includes 100.
305         Set<Integer> uidSet = Set.of(100);
306         initSharedPreference(EN_US, uidSet, 0, 0, 0, 0);
307 
308         mActivity.onLocaleSelected(mLocaleInfo);
309 
310         // Notification is triggered.
311         // In the proto file, en-US's uid list contains 101, the notificationCount equals 1, and
312         // LastNotificationTime > 0.
313         NotificationInfo info = mDataManager.getNotificationInfo(EN_US);
314         assertThat(info.getUidCollection()).contains(sUid);
315         assertThat(info.getNotificationCount()).isEqualTo(1);
316         assertThat(info.getDismissCount()).isEqualTo(0);
317         assertThat(info.getLastNotificationTimeMs()).isNotEqualTo(0);
318         verify(mFeatureFactory.metricsFeatureProvider).action(
319                 any(), eq(SettingsEnums.ACTION_NOTIFICATION_FOR_SYSTEM_LOCALE));
320 
321         mDataManager.clearLocaleNotificationMap();
322     }
323 
324     @Test
325     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
onLocaleSelected_evaluateNotification_oddLocaleUpdate_uidAddedWithoutNotification()326     public void onLocaleSelected_evaluateNotification_oddLocaleUpdate_uidAddedWithoutNotification()
327             throws Exception {
328         // App with uid 102 changed its locale from System to en-US.
329         sUid = 102;
330         initLocaleNotificationEnvironment();
331         // Initialize the proto to include en-US locale. Its uid list includes 100,101 and
332         // the notification count equals 1.
333         int notificationId = (int) SystemClock.uptimeMillis();
334         Set<Integer> uidSet = Set.of(100, 101);
335         initSharedPreference(EN_US, uidSet, 0, 1,
336                 Calendar.getInstance().getTimeInMillis(), notificationId);
337 
338         mActivity.onLocaleSelected(mLocaleInfo);
339 
340         // Notification is not triggered because count % 2 != 0.
341         // In the proto file, en-US's uid list contains 102, the notificationCount equals 1, and
342         // LastNotificationTime > 0.
343         NotificationInfo info = mDataManager.getNotificationInfo(EN_US);
344         assertThat(info.getUidCollection()).contains(sUid);
345         assertThat(info.getNotificationCount()).isEqualTo(1);
346         assertThat(info.getDismissCount()).isEqualTo(0);
347         assertThat(info.getLastNotificationTimeMs()).isNotEqualTo(0);
348         assertThat(info.getNotificationId()).isEqualTo(notificationId);
349 
350         mDataManager.clearLocaleNotificationMap();
351     }
352 
353     @Test
354     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
onLocaleSelected_evaluateNotification_frequentLocaleUpdate_uidAddedNoNotification()355     public void onLocaleSelected_evaluateNotification_frequentLocaleUpdate_uidAddedNoNotification()
356             throws Exception {
357         // App with uid 103 changed its locale from System to en-US.
358         sUid = 103;
359         initLocaleNotificationEnvironment();
360         // Initialize the proto to include en-US locale. Its uid list includes 100,101,102 and
361         // the notification count equals 1.
362         int notificationId = (int) SystemClock.uptimeMillis();
363         Set<Integer> uidSet = Set.of(100, 101, 102);
364         initSharedPreference(EN_US, uidSet, 0, 1,
365                 Calendar.getInstance().getTimeInMillis(), notificationId);
366 
367         mActivity.onLocaleSelected(mLocaleInfo);
368 
369         // Notification is not triggered because the duration is less than the threshold.
370         // In the proto file, en-US's uid list contains 103, the notificationCount equals 1, and
371         // LastNotificationTime > 0.
372         NotificationInfo info = mDataManager.getNotificationInfo(EN_US);
373         assertThat(info.getUidCollection()).contains(sUid);
374         assertThat(info.getNotificationCount()).isEqualTo(1);
375         assertThat(info.getDismissCount()).isEqualTo(0);
376         assertThat(info.getLastNotificationTimeMs()).isNotEqualTo(0);
377         assertThat(info.getNotificationId()).isEqualTo(notificationId);
378 
379         mDataManager.clearLocaleNotificationMap();
380     }
381 
382     @Test
383     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
onLocaleSelected_evaluateNotification_2ndOddLocaleUpdate_uidAddedNoNotification()384     public void onLocaleSelected_evaluateNotification_2ndOddLocaleUpdate_uidAddedNoNotification()
385             throws Exception {
386         // App with uid 104 changed its locale from System to en-US.
387         sUid = 104;
388         initLocaleNotificationEnvironment();
389 
390         // Initialize the proto to include en-US locale. Its uid list includes 100,101,102,103 and
391         // the notification count equals 1.
392         int notificationId = (int) SystemClock.uptimeMillis();
393         Set<Integer> uidSet = Set.of(100, 101, 102, 103);
394         initSharedPreference(EN_US, uidSet, 0, 1, Calendar.getInstance().getTimeInMillis(),
395                 notificationId);
396 
397         mActivity.onLocaleSelected(mLocaleInfo);
398 
399         // Notification is not triggered because uid count % 2 != 0
400         // In the proto file, en-US's uid list contains uid4, the notificationCount equals 1, and
401         // LastNotificationTime > 0.
402         NotificationInfo info = mDataManager.getNotificationInfo(EN_US);
403         assertThat(info.getUidCollection()).contains(sUid);
404         assertThat(info.getNotificationCount()).isEqualTo(1);
405         assertThat(info.getDismissCount()).isEqualTo(0);
406         assertThat(info.getLastNotificationTimeMs()).isNotEqualTo(0);
407 
408         mDataManager.clearLocaleNotificationMap();
409     }
410 
411     @Test
412     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
testEvaluateLocaleNotification_evenLocaleUpdate_trigger2ndNotification()413     public void testEvaluateLocaleNotification_evenLocaleUpdate_trigger2ndNotification()
414             throws Exception {
415         sUid = 105;
416         initLocaleNotificationEnvironment();
417 
418         // Initialize the proto to include en-US locale. Its uid list includes 100,101,102,103,104
419         // and the notification count equals 1.
420         // Eight days later, App with uid 105 changed its locale from System to en-US
421         int notificationId = (int) SystemClock.uptimeMillis();
422         Set<Integer> uidSet = Set.of(100, 101, 102, 103, 104);
423         Calendar now = Calendar.getInstance();
424         now.add(Calendar.DAY_OF_MONTH, -8); // Set the lastNotificationTime to eight days ago.
425         long lastNotificationTime = now.getTimeInMillis();
426         initSharedPreference(EN_US, uidSet, 0, 1, lastNotificationTime, notificationId);
427 
428         mActivity.onLocaleSelected(mLocaleInfo);
429 
430         // Notification is triggered.
431         // In the proto file, en-US's uid list contains 105, the notificationCount equals 2, and
432         // LastNotificationTime is updated.
433         NotificationInfo info = mDataManager.getNotificationInfo(EN_US);
434         assertThat(info.getUidCollection()).contains(sUid);
435         assertThat(info.getNotificationCount()).isEqualTo(2);
436         assertThat(info.getDismissCount()).isEqualTo(0);
437         assertThat(info.getLastNotificationTimeMs()).isGreaterThan(lastNotificationTime);
438 
439         mDataManager.clearLocaleNotificationMap();
440     }
441 
442     @Test
443     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
testEvaluateLocaleNotification_localeUpdateReachThreshold_noUidNorNotification()444     public void testEvaluateLocaleNotification_localeUpdateReachThreshold_noUidNorNotification()
445             throws Exception {
446         // App with uid 106 changed its locale from System to en-US.
447         sUid = 106;
448         initLocaleNotificationEnvironment();
449         // Initialize the proto to include en-US locale. Its uid list includes
450         // 100,101,102,103,104,105 and the notification count equals 2.
451         int notificationId = (int) SystemClock.uptimeMillis();
452         Set<Integer> uidSet = Set.of(100, 101, 102, 103, 104, 105);
453         Calendar now = Calendar.getInstance();
454         now.add(Calendar.DAY_OF_MONTH, -8);
455         long lastNotificationTime = now.getTimeInMillis();
456         initSharedPreference(EN_US, uidSet, 0, 2, lastNotificationTime, notificationId);
457 
458         mActivity.onLocaleSelected(mLocaleInfo);
459 
460         // Notification is not triggered because the notification count threshold, 2, is reached.
461         // In the proto file, en-US's uid list contains 106, the notificationCount equals 2, and
462         // LastNotificationTime > 0.
463         NotificationInfo info = mDataManager.getNotificationInfo(EN_US);
464         assertThat(info.getUidCollection().contains(sUid)).isFalse();
465         assertThat(info.getNotificationCount()).isEqualTo(2);
466         assertThat(info.getDismissCount()).isEqualTo(0);
467         assertThat(info.getLastNotificationTimeMs()).isEqualTo(lastNotificationTime);
468 
469         mDataManager.clearLocaleNotificationMap();
470     }
471 
472     @Test
473     @RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
testEvaluateLocaleNotification_appChangedLocales_newLocaleCreated()474     public void testEvaluateLocaleNotification_appChangedLocales_newLocaleCreated()
475             throws Exception {
476         sUid = 100;
477         initLocaleNotificationEnvironment();
478         // App with uid 100 changed its locale from en-US to ja-JP.
479         Locale locale = Locale.forLanguageTag("ja-JP");
480         when(mLocaleInfo.getLocale()).thenReturn(locale);
481         // Initialize the proto to include en-US locale. Its uid list includes
482         // 100,101,102,103,104,105,106 and the notification count equals 2.
483         int notificationId = (int) SystemClock.uptimeMillis();
484         Set<Integer> uidSet = Set.of(100, 101, 102, 103, 104, 105, 106);
485         Calendar now = Calendar.getInstance();
486         now.add(Calendar.DAY_OF_MONTH, -8);
487         initSharedPreference(EN_US, uidSet, 0, 2, now.getTimeInMillis(),
488                 notificationId);
489 
490         mActivity.onLocaleSelected(mLocaleInfo);
491 
492         // Notification is not triggered
493         // In the proto file, a map for ja-JP is created. Its uid list contains uid1.
494         NotificationInfo info = mDataManager.getNotificationInfo("ja-JP");
495         assertThat(info.getUidCollection()).contains(sUid);
496         assertThat(info.getNotificationCount()).isEqualTo(0);
497         assertThat(info.getDismissCount()).isEqualTo(0);
498         assertThat(info.getLastNotificationTimeMs()).isEqualTo(0);
499 
500         mDataManager.clearLocaleNotificationMap();
501     }
502 
initLocaleNotificationEnvironment()503     private void initLocaleNotificationEnvironment() throws Exception {
504         LocaleList.setDefault(LocaleList.forLanguageTags(EN_CA));
505 
506         Locale locale = Locale.forLanguageTag("en-US");
507         when(mLocaleInfo.getLocale()).thenReturn(locale);
508         when(mLocaleInfo.isSystemLocale()).thenReturn(false);
509         when(mLocaleInfo.isAppCurrentLocale()).thenReturn(false);
510 
511         ActivityController<TestAppLocalePickerActivity> controller = initActivityController(true);
512         controller.create();
513         mActivity = controller.get();
514         mDataManager = NotificationController.getInstance(mActivity).getDataManager();
515     }
516 
initSharedPreference(String locale, Set<Integer> uidSet, int dismissCount, int notificationCount, long lastNotificationTime, int notificationId)517     private void initSharedPreference(String locale, Set<Integer> uidSet, int dismissCount,
518             int notificationCount, long lastNotificationTime, int notificationId)
519             throws Exception {
520         NotificationInfo info = new NotificationInfo(uidSet, notificationCount, dismissCount,
521                 lastNotificationTime, notificationId);
522         mDataManager.putNotificationInfo(locale, info);
523     }
524 
initActivityController( boolean hasPackageName)525     private ActivityController<TestAppLocalePickerActivity> initActivityController(
526             boolean hasPackageName) {
527         Intent data = new Intent();
528         if (hasPackageName) {
529             data.setData(TEST_PACKAGE_URI);
530         }
531         data.putExtra(AppInfoBase.ARG_PACKAGE_UID, sUid);
532         ActivityController<TestAppLocalePickerActivity> activityController =
533                 Robolectric.buildActivity(TestAppLocalePickerActivity.class, data);
534         Activity activity = activityController.get();
535 
536         ShadowTelephonyManager shadowTelephonyManager = Shadows.shadowOf(
537                 activity.getSystemService(TelephonyManager.class));
538         shadowTelephonyManager.setSimCountryIso("US");
539         shadowTelephonyManager.setNetworkCountryIso("US");
540 
541         return activityController;
542     }
543 
544     private static class TestAppLocalePickerActivity extends AppLocalePickerActivity {
545         @Override
createContextAsUser(UserHandle user, int flags)546         public Context createContextAsUser(UserHandle user, int flags) {
547             // return the current context as a work profile
548             return this;
549         }
550     }
551 
552     @Implements(ApplicationPackageManager.class)
553     public static class ShadowApplicationPackageManager extends
554             org.robolectric.shadows.ShadowApplicationPackageManager {
555         private static boolean sNoLaunchEntry = false;
556 
557         @Implementation
getInstallSourceInfo(String packageName)558         protected Object getInstallSourceInfo(String packageName) {
559             return new InstallSourceInfo("", null, null, "");
560         }
561 
562         @Implementation
queryIntentActivities(Intent intent, int flags)563         protected List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
564             if (sNoLaunchEntry) {
565                 return new ArrayList();
566             } else {
567                 return super.queryIntentActivities(intent, flags);
568             }
569         }
570 
setNoLaunchEntry(boolean noLaunchEntry)571         private static void setNoLaunchEntry(boolean noLaunchEntry) {
572             sNoLaunchEntry = noLaunchEntry;
573         }
574 
575         @Implementation
getApplicationInfo(String packageName, int flags)576         protected ApplicationInfo getApplicationInfo(String packageName, int flags)
577                 throws NameNotFoundException {
578             if (packageName.equals(TEST_PACKAGE_NAME)) {
579                 ApplicationInfo applicationInfo = new ApplicationInfo();
580                 applicationInfo.packageName = TEST_PACKAGE_NAME;
581                 applicationInfo.uid = sUid;
582                 return applicationInfo;
583             } else {
584                 return super.getApplicationInfo(packageName, flags);
585             }
586         }
587     }
588 
589     @Implements(Resources.class)
590     public static class ShadowResources extends
591             org.robolectric.shadows.ShadowResources {
592         private static boolean sDisAllowPackage = false;
593 
594         @Implementation
getStringArray(@rrayRes int id)595         public String[] getStringArray(@ArrayRes int id) {
596             if (sDisAllowPackage) {
597                 return new String[]{TEST_PACKAGE_NAME};
598             } else {
599                 return new String[0];
600             }
601         }
602 
setDisAllowPackage(boolean disAllowPackage)603         private static void setDisAllowPackage(boolean disAllowPackage) {
604             sDisAllowPackage = disAllowPackage;
605         }
606     }
607 }
608