1 /*
2  * Copyright (C) 2016 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.cellbroadcastreceiver.unit;
18 
19 import static org.mockito.ArgumentMatchers.any;
20 import static org.mockito.ArgumentMatchers.anyBoolean;
21 import static org.mockito.ArgumentMatchers.anyInt;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.ArgumentMatchers.nullable;
24 import static org.mockito.Mockito.atLeastOnce;
25 import static org.mockito.Mockito.doAnswer;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30 
31 import android.app.ActivityManager;
32 import android.app.ActivityOptions;
33 import android.app.ContentProviderHolder;
34 import android.app.IActivityManager;
35 import android.app.Notification;
36 import android.app.NotificationManager;
37 import android.app.PendingIntent;
38 import android.content.IContentProvider;
39 import android.content.Intent;
40 import android.content.SharedPreferences;
41 import android.content.pm.ApplicationInfo;
42 import android.content.pm.ProviderInfo;
43 import android.content.res.Configuration;
44 import android.content.res.Resources;
45 import android.os.Bundle;
46 import android.os.IBinder;
47 import android.os.IPowerManager;
48 import android.os.IThermalService;
49 import android.os.Looper;
50 import android.os.Message;
51 import android.os.PowerManager;
52 import android.os.RemoteException;
53 import android.telephony.SmsCbMessage;
54 import android.telephony.SubscriptionInfo;
55 import android.telephony.SubscriptionManager;
56 import android.text.TextUtils;
57 import android.util.Singleton;
58 import android.view.IWindowManager;
59 import android.view.KeyEvent;
60 import android.view.View;
61 import android.view.ViewGroup;
62 import android.view.WindowManager;
63 import android.view.WindowManagerGlobal;
64 import android.widget.ImageView;
65 import android.widget.LinearLayout;
66 import android.widget.TextView;
67 
68 import com.android.cellbroadcastreceiver.CellBroadcastAlertDialog;
69 import com.android.cellbroadcastreceiver.CellBroadcastAlertService;
70 import com.android.cellbroadcastreceiver.CellBroadcastChannelManager;
71 import com.android.cellbroadcastreceiver.CellBroadcastReceiverApp;
72 import com.android.cellbroadcastreceiver.CellBroadcastSettings;
73 import com.android.cellbroadcastreceiver.R;
74 import com.android.internal.telephony.gsm.SmsCbConstants;
75 import com.android.modules.utils.build.SdkLevel;
76 
77 import org.junit.After;
78 import org.junit.Before;
79 import org.mockito.ArgumentCaptor;
80 import org.mockito.Captor;
81 import org.mockito.Mock;
82 import org.mockito.MockitoAnnotations;
83 import org.mockito.invocation.InvocationOnMock;
84 import org.mockito.stubbing.Answer;
85 
86 import java.lang.reflect.Field;
87 import java.lang.reflect.Method;
88 import java.util.ArrayList;
89 
90 public class CellBroadcastAlertDialogTest extends
91         CellBroadcastActivityTestCase<CellBroadcastAlertDialog> {
92 
93     @Mock
94     private NotificationManager mMockedNotificationManager;
95 
96     @Mock
97     private IPowerManager.Stub mMockedPowerManagerService;
98 
99     @Mock
100     private IThermalService.Stub mMockedThermalService;
101 
102     @Mock
103     private IActivityManager.Stub mMockedActivityManager;
104 
105     @Mock
106     IWindowManager.Stub mWindowManagerService;
107 
108     @Mock
109     LinearLayout mMockLinearLayout;
110 
111     @Captor
112     private ArgumentCaptor<Integer> mFlags;
113 
114     @Captor
115     private ArgumentCaptor<Integer> mInt;
116 
117     @Captor
118     private ArgumentCaptor<Notification> mNotification;
119 
120     private PowerManager mPowerManager;
121     private int mSubId = 0;
122 
CellBroadcastAlertDialogTest()123     public CellBroadcastAlertDialogTest() {
124         super(CellBroadcastAlertDialog.class);
125     }
126 
127     private int mServiceCategory = SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL;
128     private int mCmasMessageClass = 0;
129 
130     private ArrayList<SmsCbMessage> mMessageList;
131 
132     MockedServiceManager mMockedActivityManagerHelper;
133 
134     @Override
createActivityIntent()135     protected Intent createActivityIntent() {
136         mMessageList = new ArrayList<>(1);
137         mMessageList.add(CellBroadcastAlertServiceTest.createMessageForCmasMessageClass(12412,
138                 mServiceCategory,
139                 mCmasMessageClass));
140 
141         Intent intent = new Intent(getInstrumentation().getTargetContext(),
142                 CellBroadcastAlertDialog.class);
143         intent.putParcelableArrayListExtra(CellBroadcastAlertService.SMS_CB_MESSAGE_EXTRA,
144                 mMessageList);
145         return intent;
146     }
147 
148     @Before
setUp()149     public void setUp() throws Exception {
150         super.setUp();
151         MockitoAnnotations.initMocks(this);
152         injectSystemService(NotificationManager.class, mMockedNotificationManager);
153         // PowerManager is a final class so we can't use Mockito to mock it, but we can mock
154         // its underlying service.
155         doReturn(true).when(mMockedPowerManagerService).isInteractive();
156         if (SdkLevel.isAtLeastU()) {
157             doReturn(true).when(
158                     mMockedPowerManagerService).isDisplayInteractive(anyInt());
159         }
160         mPowerManager = new PowerManager(mContext, mMockedPowerManagerService,
161                 mMockedThermalService, null);
162         injectSystemService(PowerManager.class, mPowerManager);
163 
164         SubscriptionManager mockSubManager = mock(SubscriptionManager.class);
165         injectSystemService(SubscriptionManager.class, mockSubManager);
166         SubscriptionInfo mockSubInfo = mock(SubscriptionInfo.class);
167         doReturn(mockSubInfo).when(mockSubManager).getActiveSubscriptionInfo(anyInt());
168 
169         CellBroadcastSettings.resetResourcesCache();
170         CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
171         String[] values = new String[]{"0x1112-0x1112:rat=gsm, always_on=true"};
172         doReturn(values).when(mContext.getResources()).getStringArray(
173                 eq(com.android.cellbroadcastreceiver.R.array
174                 .cmas_presidential_alerts_channels_range_strings));
175     }
176 
177     @After
tearDown()178     public void tearDown() throws Exception {
179         CellBroadcastSettings.resetResourcesCache();
180         CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
181         super.tearDown();
182     }
183 
testTitleAndMessageText()184     public void testTitleAndMessageText() throws Throwable {
185         doReturn(true).when(mContext.getResources()).getBoolean(R.bool.show_alert_title);
186 
187         startActivity();
188         waitForMs(100);
189 
190         CharSequence alertString =
191                 getActivity().getResources().getText(com.android.cellbroadcastreceiver.R.string
192                         .cmas_presidential_level_alert);
193         assertTrue(getActivity().getTitle().toString().startsWith(alertString.toString()));
194         assertTrue(((TextView) getActivity().findViewById(
195                 com.android.cellbroadcastreceiver.R.id.alertTitle)).getText().toString()
196                 .startsWith(alertString.toString()));
197 
198         waitUntilAssertPasses(()-> {
199             String body = CellBroadcastAlertServiceTest.createMessage(34596).getMessageBody();
200             assertEquals(body, ((TextView) getActivity().findViewById(
201                             com.android.cellbroadcastreceiver.R.id.message)).getText().toString());
202         }, 1000);
203 
204         stopActivity();
205     }
testNoTitle()206     public void testNoTitle() throws Throwable {
207         doReturn(false).when(mContext.getResources()).getBoolean(R.bool.show_alert_title);
208         startActivity();
209         waitForMs(100);
210         assertTrue(TextUtils.isEmpty(((TextView) getActivity().findViewById(
211                 com.android.cellbroadcastreceiver.R.id.alertTitle)).getText()));
212         stopActivity();
213     }
214 
waitUntilAssertPasses(Runnable r, long maxWaitMs)215     public void waitUntilAssertPasses(Runnable r, long maxWaitMs) {
216         long waitTime = 0;
217         while (waitTime < maxWaitMs) {
218             try {
219                 r.run();
220                 // if the assert succeeds, return
221                 return;
222             } catch (Exception e) {
223                 waitTime += 100;
224                 waitForMs(100);
225             }
226         }
227         // if timed out, run one last time without catching exception
228         r.run();
229     }
230 
testAddToNotification()231     public void testAddToNotification() throws Throwable {
232         setUpMockActivityManager();
233 
234         doReturn(true).when(mContext.getResources()).getBoolean(R.bool.show_alert_title);
235         doReturn(false).when(mContext.getResources()).getBoolean(
236                 R.bool.disable_capture_alert_dialog);
237 
238         startActivity();
239         waitForMs(100);
240         leaveActivity();
241         waitForMs(100);
242         verify(mMockedNotificationManager, times(1)).notify(mInt.capture(),
243                 mNotification.capture());
244         Bundle b = mNotification.getValue().extras;
245 
246         assertEquals(Notification.VISIBILITY_PUBLIC, mNotification.getValue().visibility);
247 
248         assertEquals(1, (int) mInt.getValue());
249 
250         assertTrue(getActivity().getTitle().toString().startsWith(
251                 b.getCharSequence(Notification.EXTRA_TITLE).toString()));
252         assertEquals(CellBroadcastAlertServiceTest.createMessage(98235).getMessageBody(),
253                 b.getCharSequence(Notification.EXTRA_TEXT));
254 
255         ArgumentCaptor<Bundle> bundleArgs = ArgumentCaptor.forClass(Bundle.class);
256         verify(mMockedActivityManager, times(2))
257                 .getIntentSenderWithFeature(anyInt(), any(), any(), any(), any(), anyInt(),
258                         any(), any(), mFlags.capture(), bundleArgs.capture(), anyInt());
259 
260         assertTrue((PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)
261                 ==  mFlags.getAllValues().get(0));
262         assertTrue((PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)
263                 ==  mFlags.getAllValues().get(1));
264 
265         if (SdkLevel.isAtLeastU()) {
266             ActivityOptions activityOptions = new ActivityOptions(bundleArgs.getAllValues().get(0));
267             int startMode = activityOptions.getPendingIntentCreatorBackgroundActivityStartMode();
268             assertEquals(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED, startMode);
269             activityOptions = new ActivityOptions(bundleArgs.getAllValues().get(1));
270             startMode = activityOptions.getPendingIntentCreatorBackgroundActivityStartMode();
271             assertEquals(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED, startMode);
272         }
273 
274         Field field = ((Class) WindowManagerGlobal.class).getDeclaredField("sWindowManagerService");
275         field.setAccessible(true);
276         field.set(null, null);
277 
278         mMockedActivityManagerHelper.restoreAllServices();
279     }
280 
setUpMockActivityManager()281     private void setUpMockActivityManager() throws Exception {
282         ProviderInfo providerInfo = new ProviderInfo();
283         providerInfo.authority = "test";
284         providerInfo.applicationInfo = new ApplicationInfo();
285         providerInfo.applicationInfo.uid = 999;
286         ContentProviderHolder holder = new ContentProviderHolder(providerInfo);
287         doReturn(holder).when(mMockedActivityManager)
288                 .getContentProvider(any(), any(), any(), anyInt(), anyBoolean());
289         holder.provider = mock(IContentProvider.class);
290 
291         Singleton<IActivityManager> activityManagerSingleton = new Singleton<IActivityManager>() {
292             @Override
293             protected IActivityManager create() {
294                 return mMockedActivityManager;
295             }
296         };
297         mMockedActivityManagerHelper = new MockedServiceManager();
298         mMockedActivityManagerHelper.replaceService("window", mWindowManagerService);
299         Field fieldHandler = ActivityManager.class.getDeclaredField("IActivityManagerSingleton");
300         fieldHandler.setAccessible(true);
301         Singleton<IActivityManager> activityManager =
302                 (Singleton<IActivityManager>) fieldHandler.get(null);
303         IActivityManager realInstance = activityManager.get();
304         doAnswer(new Answer() {
305             public Void answer(InvocationOnMock invocation) throws RemoteException {
306                 if (realInstance != null) {
307                     realInstance.finishReceiver(invocation.getArgument(0),
308                             invocation.getArgument(1), invocation.getArgument(2),
309                             invocation.getArgument(3), invocation.getArgument(4),
310                             invocation.getArgument(5));
311                 }
312                 return null;
313             }
314         }).when(mMockedActivityManager).finishReceiver(nullable(IBinder.class), anyInt(),
315                 nullable(String.class), nullable(Bundle.class), anyBoolean(), anyInt());
316         mMockedActivityManagerHelper.replaceInstance(ActivityManager.class,
317                 "IActivityManagerSingleton", null, activityManagerSingleton);
318     }
319 
testAddToNotificationWithDifferentConfiguration()320     public void testAddToNotificationWithDifferentConfiguration() throws Throwable {
321         doReturn(false).when(mContext.getResources()).getBoolean(R.bool.show_alert_title);
322         doReturn(true).when(mContext.getResources()).getBoolean(
323                 R.bool.disable_capture_alert_dialog);
324 
325         startActivity();
326         waitForMs(100);
327         leaveActivity();
328         waitForMs(100);
329         verify(mMockedNotificationManager, times(1)).notify(mInt.capture(),
330                 mNotification.capture());
331         Bundle b = mNotification.getValue().extras;
332 
333         assertEquals(Notification.VISIBILITY_PUBLIC, mNotification.getValue().visibility);
334         assertEquals(1, (int) mInt.getValue());
335         assertTrue(TextUtils.isEmpty(b.getCharSequence(Notification.EXTRA_TITLE)));
336         verify(mContext.getResources(), times(1)).getString(mInt.capture(), anyInt());
337         assertEquals(R.string.notification_multiple, (int) mInt.getValue());
338     }
339 
testDoNotAddToNotificationOnStop()340     public void testDoNotAddToNotificationOnStop() throws Throwable {
341         startActivity();
342         waitForMs(100);
343         stopActivity();
344         waitForMs(100);
345         verify(mMockedNotificationManager, times(0)).notify(mInt.capture(),
346                 mNotification.capture());
347     }
348 
testDismissByDeleteIntent()349     public void testDismissByDeleteIntent() throws Throwable {
350         final Intent intent = createActivityIntent();
351         intent.putExtra(CellBroadcastAlertService.DISMISS_DIALOG, true);
352         intent.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, true);
353         Looper.prepare();
354         CellBroadcastAlertDialog activity =
355                 startActivity(intent, null, null);
356         getInstrumentation().callActivityOnUserLeaving(activity);
357         verify(mMockedNotificationManager, atLeastOnce()).cancel(
358                 eq(CellBroadcastAlertService.NOTIFICATION_ID));
359     }
360 
testGetNewMessageListIfNeeded()361     public void testGetNewMessageListIfNeeded() throws Throwable {
362         CellBroadcastAlertDialog activity = startActivity();
363         Resources spyRes = mContext.getResources();
364         doReturn(false).when(spyRes).getBoolean(
365                 R.bool.show_cmas_messages_in_priority_order);
366 
367         SmsCbMessage testMessage1 = CellBroadcastAlertServiceTest
368                 .createMessageForCmasMessageClass(12412,
369                         SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL,
370                         mCmasMessageClass);
371         waitForMs(10);
372         SmsCbMessage testMessage2 = CellBroadcastAlertServiceTest
373                 .createMessageForCmasMessageClass(12412,
374                         SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY,
375                         mCmasMessageClass);
376         ArrayList<SmsCbMessage> inputList1 = new ArrayList<>();
377         ArrayList<SmsCbMessage> inputList2 = new ArrayList<>();
378 
379         inputList1.add(testMessage1);
380         ArrayList<SmsCbMessage> messageList = activity.getNewMessageListIfNeeded(
381                 inputList1, inputList2);
382         assertTrue(messageList.size() == 1);
383         assertEquals(testMessage1.getReceivedTime(), messageList.get(0).getReceivedTime());
384 
385         inputList2.add(testMessage1);
386         messageList = activity.getNewMessageListIfNeeded(inputList1, inputList2);
387         assertTrue(messageList.size() == 1);
388         assertEquals(testMessage1.getReceivedTime(), messageList.get(0).getReceivedTime());
389 
390         inputList2.add(testMessage2);
391         messageList = activity.getNewMessageListIfNeeded(inputList1, inputList2);
392         assertTrue(messageList.size() == 2);
393         assertEquals(testMessage2.getReceivedTime(), messageList.get(1).getReceivedTime());
394 
395         doReturn(true).when(spyRes).getBoolean(
396                 R.bool.show_cmas_messages_in_priority_order);
397 
398         messageList = activity.getNewMessageListIfNeeded(inputList1, inputList2);
399         assertTrue(messageList.size() == 2);
400         assertEquals(testMessage1.getReceivedTime(), messageList.get(1).getReceivedTime());
401     }
402 
403     @InstrumentationTest
404     // This test has a module dependency (it uses the CellBroadcastContentProvider), so it is
405     // disabled for OEM testing because it is not a true unit test
testDismiss()406     public void testDismiss() throws Throwable {
407         CellBroadcastAlertDialog activity = startActivity();
408         waitForMs(100);
409         activity.dismiss();
410 
411         verify(mMockedNotificationManager, times(1)).cancel(
412                 eq(CellBroadcastAlertService.NOTIFICATION_ID));
413     }
414 
testOnNewIntent()415     public void testOnNewIntent() throws Throwable {
416         Intent intent = createActivityIntent();
417         intent.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, true);
418 
419         Looper.prepare();
420         CellBroadcastAlertDialog activity = startActivity(intent, null, null);
421         waitForMs(100);
422 
423         ImageView image = activity.findViewById(R.id.pictogramImage);
424         image.setVisibility(View.VISIBLE);
425         assertEquals(View.VISIBLE, image.getVisibility());
426 
427         // add more messages to list
428         mMessageList.add(CellBroadcastAlertServiceTest.createMessageForCmasMessageClass(12413,
429                 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING,
430                 SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING));
431         intent.putParcelableArrayListExtra(CellBroadcastAlertService.SMS_CB_MESSAGE_EXTRA,
432                 new ArrayList<>(mMessageList));
433         activity.onNewIntent(intent);
434 
435         verify(mMockedNotificationManager, atLeastOnce()).cancel(
436                 eq(CellBroadcastAlertService.NOTIFICATION_ID));
437         assertNotNull(image.getLayoutParams());
438     }
439 
testAnimationHandler()440     public void testAnimationHandler() throws Throwable {
441         CellBroadcastAlertDialog activity = startActivity();
442 
443         activity.mAnimationHandler.startIconAnimation(mSubId);
444 
445         assertTrue(activity.mAnimationHandler.mWarningIconVisible);
446 
447         Message m = Message.obtain();
448         m.what = activity.mAnimationHandler.mCount.get();
449         activity.mAnimationHandler.handleMessage(m);
450 
451         // assert that message count has gone up
452         assertEquals(m.what + 1, activity.mAnimationHandler.mCount.get());
453     }
454 
testOnResume()455     public void testOnResume() throws Throwable {
456         Intent intent = createActivityIntent();
457         intent.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, true);
458 
459         Looper.prepare();
460         CellBroadcastAlertDialog activity = startActivity(intent, null, null);
461 
462         CellBroadcastAlertDialog.AnimationHandler mockAnimationHandler = mock(
463                 CellBroadcastAlertDialog.AnimationHandler.class);
464         activity.mAnimationHandler = mockAnimationHandler;
465 
466         activity.onResume();
467         verify(mockAnimationHandler).startIconAnimation(anyInt());
468     }
469 
testOnPause()470     public void testOnPause() throws Throwable {
471         Intent intent = createActivityIntent();
472         intent.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, true);
473 
474         Looper.prepare();
475         CellBroadcastAlertDialog activity = startActivity(intent, null, null);
476 
477         CellBroadcastAlertDialog.AnimationHandler mockAnimationHandler = mock(
478                 CellBroadcastAlertDialog.AnimationHandler.class);
479         activity.mAnimationHandler = mockAnimationHandler;
480 
481         activity.onPause();
482         verify(mockAnimationHandler).stopIconAnimation();
483     }
484 
testOnKeyDown()485     public void testOnKeyDown() throws Throwable {
486         Intent intent = createActivityIntent();
487         intent.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, true);
488 
489         Looper.prepare();
490         CellBroadcastAlertDialog activity = startActivity(intent, null, null);
491 
492         assertTrue(activity.onKeyDown(0,
493                 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FOCUS)));
494     }
495 
testOnConfigurationChanged()496     public void testOnConfigurationChanged() throws Throwable {
497         CellBroadcastAlertDialog activity = startActivity();
498         Configuration newConfig = new Configuration();
499 
500         ImageView image = activity.findViewById(R.id.pictogramImage);
501         image.setVisibility(View.VISIBLE);
502         assertEquals(View.VISIBLE, image.getVisibility());
503 
504         newConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
505         activity.onConfigurationChanged(newConfig);
506         assertNotNull(image.getLayoutParams());
507 
508         newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
509         activity.onConfigurationChanged(newConfig);
510         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, image.getLayoutParams().height);
511         assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, image.getLayoutParams().width);
512     }
513 
testOnWindowFocusChanged()514     public void testOnWindowFocusChanged() throws Throwable {
515         CellBroadcastAlertDialog activity = startActivity();
516 
517         ImageView image = activity.findViewById(R.id.pictogramImage);
518         image.setVisibility(View.VISIBLE);
519         assertEquals(View.VISIBLE, image.getVisibility());
520 
521         activity.onWindowFocusChanged(true);
522         assertNotNull(image.getLayoutParams());
523     }
524 
testOnKeyDownWithEmptyMessageList()525     public void testOnKeyDownWithEmptyMessageList() throws Throwable {
526         mMessageList = new ArrayList<>(1);
527 
528         Intent intent = new Intent(getInstrumentation().getTargetContext(),
529                 CellBroadcastAlertDialog.class);
530         intent.putParcelableArrayListExtra(CellBroadcastAlertService.SMS_CB_MESSAGE_EXTRA,
531                 mMessageList);
532         intent.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, true);
533         Looper.prepare();
534         CellBroadcastAlertDialog activity = startActivity(intent, null, null);
535 
536         assertTrue(activity.onKeyDown(0,
537                 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FOCUS)));
538     }
539 
testPulsationHandlerStart()540     public void testPulsationHandlerStart() throws Throwable {
541         int[] pattern = new int[] {0xFFFF0000, 100000, 500, 1000};
542         doReturn(pattern).when(mContext.getResources()).getIntArray(
543                 eq(com.android.cellbroadcastreceiver.R.array.default_pulsation_pattern));
544 
545         CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
546         CellBroadcastAlertDialog activity = startActivity();
547         waitForMs(100);
548         activity.mPulsationHandler.mLayout = mMockLinearLayout;
549 
550         assertEquals(0xFFFF0000, activity.mPulsationHandler.mHighlightColor);
551         assertEquals(100000, activity.mPulsationHandler.mDuration);
552         assertEquals(500, activity.mPulsationHandler.mOnInterval);
553         assertEquals(1000, activity.mPulsationHandler.mOffInterval);
554 
555         waitForMs(2000);
556 
557         verify(mMockLinearLayout, atLeastOnce()).setBackgroundColor(eq(0xFFFF0000));
558     }
559 
testPulsationRestartOnNewIntent()560     public void testPulsationRestartOnNewIntent() throws Throwable {
561         int[] pattern = new int[] {0xFFFF0000, 100000, 500, 1000};
562         doReturn(pattern).when(mContext.getResources()).getIntArray(
563                 eq(com.android.cellbroadcastreceiver.R.array.default_pulsation_pattern));
564 
565         CellBroadcastAlertDialog activity = startActivity();
566         waitForMs(100);
567         activity.mPulsationHandler.mLayout = mMockLinearLayout;
568 
569         assertEquals(0xFFFF0000, activity.mPulsationHandler.mHighlightColor);
570         assertEquals(100000, activity.mPulsationHandler.mDuration);
571         assertEquals(500, activity.mPulsationHandler.mOnInterval);
572         assertEquals(1000, activity.mPulsationHandler.mOffInterval);
573 
574         pattern = new int[] {0xFFFFFFFF, 200000, 1000, 500};
575         doReturn(pattern).when(mContext.getResources()).getIntArray(
576                 eq(com.android.cellbroadcastreceiver.R.array.default_pulsation_pattern));
577         mMessageList.add(CellBroadcastAlertServiceTest.createMessageForCmasMessageClass(12413,
578                 SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY,
579                 SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY));
580         Intent intent = createActivityIntent();
581         intent.putParcelableArrayListExtra(CellBroadcastAlertService.SMS_CB_MESSAGE_EXTRA,
582                 new ArrayList<>(mMessageList));
583         CellBroadcastSettings.resetResourcesCache();
584         CellBroadcastChannelManager.clearAllCellBroadcastChannelRanges();
585         activity.onNewIntent(intent);
586         waitForMs(100);
587 
588         // Verify existing pulsation has been stopped
589         verify(mMockLinearLayout, times(1)).setBackgroundColor(
590                 eq(activity.mPulsationHandler.mBackgroundColor));
591 
592         activity.mPulsationHandler.mLayout = mMockLinearLayout;
593 
594         // Verify new parameters have been applied
595         assertEquals(0xFFFFFFFF, activity.mPulsationHandler.mHighlightColor);
596         assertEquals(200000, activity.mPulsationHandler.mDuration);
597         assertEquals(1000, activity.mPulsationHandler.mOnInterval);
598         assertEquals(500, activity.mPulsationHandler.mOffInterval);
599 
600         waitForMs(2000);
601 
602         // Verify new pulsation takes effect
603         verify(mMockLinearLayout, atLeastOnce()).setBackgroundColor(eq(0xFFFFFFFF));
604     }
605 
testPulsationHandlerHandleMessageAndStop()606     public void testPulsationHandlerHandleMessageAndStop() throws Throwable {
607         CellBroadcastAlertDialog activity = startActivity();
608         waitForMs(100);
609 
610         int backgroundColor = activity.mPulsationHandler.mBackgroundColor;
611         activity.mPulsationHandler.mHighlightColor = 0xFFFF0000;
612         activity.mPulsationHandler.mLayout = mMockLinearLayout;
613         activity.mPulsationHandler.mOnInterval = 60000;
614         activity.mPulsationHandler.mOffInterval = 60000;
615         activity.mPulsationHandler.mDuration = 300000;
616 
617         Message m = Message.obtain();
618         m.what = activity.mPulsationHandler.mCount.get();
619         activity.mPulsationHandler.handleMessage(m);
620 
621         // assert that message count has gone up, and the background color is highlighted
622         assertEquals(m.what + 1, activity.mPulsationHandler.mCount.get());
623         assertTrue(activity.mPulsationHandler.mIsPulsationOn);
624         verify(mMockLinearLayout, times(1)).setBackgroundColor(eq(0xFFFF0000));
625 
626         m = Message.obtain();
627         m.what = activity.mPulsationHandler.mCount.get();
628         activity.mPulsationHandler.handleMessage(m);
629 
630         // assert that message count has gone up, and the background color is restored
631         assertEquals(m.what + 1, activity.mPulsationHandler.mCount.get());
632         assertFalse(activity.mPulsationHandler.mIsPulsationOn);
633         verify(mMockLinearLayout, times(1)).setBackgroundColor(eq(backgroundColor));
634 
635         m = Message.obtain();
636         m.what = activity.mPulsationHandler.mCount.get();
637         activity.mPulsationHandler.handleMessage(m);
638 
639         // assert that the background color is highlighted again
640         assertEquals(m.what + 1, activity.mPulsationHandler.mCount.get());
641         assertTrue(activity.mPulsationHandler.mIsPulsationOn);
642         verify(mMockLinearLayout, times(2)).setBackgroundColor(eq(0xFFFF0000));
643 
644         activity.mPulsationHandler.stop();
645         waitForMs(100);
646 
647         // assert that the background color is restored
648         assertEquals(m.what + 2, activity.mPulsationHandler.mCount.get());
649         assertFalse(activity.mPulsationHandler.mIsPulsationOn);
650         verify(mMockLinearLayout, times(2)).setBackgroundColor(eq(backgroundColor));
651     }
652 
getNewMessageList()653     private ArrayList<SmsCbMessage> getNewMessageList() throws Exception {
654         Method method = CellBroadcastReceiverApp.class.getDeclaredMethod("getNewMessageList");
655         method.setAccessible(true);
656         return (ArrayList<SmsCbMessage>) method.invoke(null);
657     }
658 
addNewMessageToList(SmsCbMessage message)659     private ArrayList<SmsCbMessage> addNewMessageToList(SmsCbMessage message) {
660         Class[] args = new Class[1];
661         args[0] = SmsCbMessage.class;
662         try {
663             Method method = CellBroadcastReceiverApp.class.getDeclaredMethod(
664                     "addNewMessageToList", args);
665             method.setAccessible(true);
666             return (ArrayList<SmsCbMessage>) method.invoke(null, message);
667         } catch (Exception e) {
668             return null;
669         }
670     }
671 
testNewMessageListCount()672     public void testNewMessageListCount() throws Throwable {
673         SmsCbMessage testMessage1 = CellBroadcastAlertServiceTest
674                 .createMessageForCmasMessageClass(75103,
675                         SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL,
676                         mCmasMessageClass);
677         SmsCbMessage testMessage2 = CellBroadcastAlertServiceTest
678                 .createMessageForCmasMessageClass(51030,
679                         SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY,
680                         mCmasMessageClass);
681         SmsCbMessage testMessage3 = CellBroadcastAlertServiceTest
682                 .createMessageForCmasMessageClass(10307,
683                         SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY,
684                         mCmasMessageClass);
685 
686         // touch a notification for on-going message
687         Intent intent1 = createActivityIntent();
688         intent1.putExtra(CellBroadcastAlertService.DISMISS_DIALOG, false);
689         intent1.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, false);
690         addNewMessageToList(testMessage1);
691         Looper.prepare();
692         CellBroadcastAlertDialog activity = startActivity(intent1, null, null);
693         waitForMs(100);
694 
695         assertEquals(1, getNewMessageList().size());
696 
697         // touch a notification for pending message
698         Intent intent2 = createActivityIntent();
699         intent2.putExtra(CellBroadcastAlertService.DISMISS_DIALOG, false);
700         intent2.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, true);
701         addNewMessageToList(testMessage2);
702         activity.onNewIntent(intent2);
703 
704         assertEquals(2, getNewMessageList().size());
705 
706         // swipe a notification for pending message
707         Intent intent3 = createActivityIntent();
708         intent3.putExtra(CellBroadcastAlertService.DISMISS_DIALOG, true);
709         intent3.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, true);
710         addNewMessageToList(testMessage3);
711         activity.onNewIntent(intent3);
712 
713         assertEquals(getNewMessageList().size(), 0);
714 
715         // swipe a notification for on-going message
716         Intent intent4 = createActivityIntent();
717         intent4.putExtra(CellBroadcastAlertService.DISMISS_DIALOG, true);
718         intent4.putExtra(CellBroadcastAlertDialog.DISMISS_NOTIFICATION_EXTRA, false);
719         addNewMessageToList(testMessage1);
720         activity.onNewIntent(intent4);
721 
722         assertEquals(getNewMessageList().size(), 1);
723     }
724 
setWatchUiMode()725     private void setWatchUiMode() {
726         Configuration configuration = new Configuration(
727                 mContext.getResources().getConfiguration());
728         configuration.uiMode =
729                 (configuration.uiMode & ~Configuration.UI_MODE_TYPE_MASK)
730                 | Configuration.UI_MODE_TYPE_WATCH;
731         mContext.enableOverrideConfiguration(true);
732         mContext = (TestContext) mContext.createConfigurationContext(configuration);
733         setActivityContext(mContext);
734     }
735 
testOnConfigurationChangedForWatch()736     public void testOnConfigurationChangedForWatch() throws Throwable {
737         setWatchUiMode();
738         CellBroadcastAlertDialog activity = startActivity();
739 
740         Configuration newConfig = new Configuration();
741         newConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
742         activity.onConfigurationChanged(newConfig);
743 
744         newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
745         activity.onConfigurationChanged(newConfig);
746 
747         assertNull(activity.findViewById(R.id.pictogramImage));
748     }
749 
testOnCreate()750     public void testOnCreate() throws Throwable {
751         doReturn(false).when(mContext.getResources()).getBoolean(
752                 R.bool.disable_capture_alert_dialog);
753         CellBroadcastAlertDialog activity = startActivity();
754         int flags = activity.getWindow().getAttributes().flags;
755         assertEquals((flags & WindowManager.LayoutParams.FLAG_SECURE), 0);
756         stopActivity();
757     }
758 
testOnCreateWithCaptureRestriction()759     public void testOnCreateWithCaptureRestriction() throws Throwable {
760         doReturn(true).when(mContext.getResources()).getBoolean(
761                 R.bool.disable_capture_alert_dialog);
762         CellBroadcastAlertDialog activity = startActivity();
763         int flags = activity.getWindow().getAttributes().flags;
764         assertEquals((flags & WindowManager.LayoutParams.FLAG_SECURE),
765                 WindowManager.LayoutParams.FLAG_SECURE);
766         stopActivity();
767     }
768 
testTitleOnNonDefaultSubId()769     public void testTitleOnNonDefaultSubId() throws Throwable {
770         Intent intent = createActivityIntent();
771         Looper.prepare();
772         CellBroadcastAlertDialog activity = startActivity(intent, null, null);
773         waitForMs(100);
774 
775         assertFalse(TextUtils.isEmpty(((TextView) getActivity().findViewById(
776                 com.android.cellbroadcastreceiver.R.id.alertTitle)).getText()));
777 
778         SharedPreferences mockSharedPreferences = mock(SharedPreferences.class);
779         doReturn("334090").when(mockSharedPreferences).getString(any(), any());
780         mContext.injectSharedPreferences(mockSharedPreferences);
781         Resources mockResources2 = mock(Resources.class);
782         doReturn(false).when(mockResources2).getBoolean(R.bool.show_alert_title);
783         doReturn("none").when(mockResources2).getString(R.string.link_method);
784 
785         CellBroadcastSettings.sResourcesCacheByOperator.put("334090", mockResources2);
786 
787         mMessageList.add(CellBroadcastAlertServiceTest.createMessageForCmasMessageClass(12413,
788                 SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY,
789                 SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY));
790         intent.putParcelableArrayListExtra(CellBroadcastAlertService.SMS_CB_MESSAGE_EXTRA,
791                 new ArrayList<>(mMessageList));
792         activity.onNewIntent(intent);
793 
794         assertTrue(TextUtils.isEmpty(((TextView) getActivity().findViewById(
795                 com.android.cellbroadcastreceiver.R.id.alertTitle)).getText()));
796     }
797 }
798