• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.server.connectivity;
18 
19 import static android.app.Notification.FLAG_AUTO_CANCEL;
20 import static android.app.Notification.FLAG_ONGOING_EVENT;
21 
22 import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.LOST_INTERNET;
23 import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.NETWORK_SWITCH;
24 import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.NO_INTERNET;
25 import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.PARTIAL_CONNECTIVITY;
26 import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.PRIVATE_DNS_BROKEN;
27 import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.SIGN_IN;
28 
29 import static org.junit.Assert.assertEquals;
30 import static org.junit.Assert.assertTrue;
31 import static org.mockito.Mockito.any;
32 import static org.mockito.Mockito.anyInt;
33 import static org.mockito.Mockito.clearInvocations;
34 import static org.mockito.Mockito.doReturn;
35 import static org.mockito.Mockito.eq;
36 import static org.mockito.Mockito.mock;
37 import static org.mockito.Mockito.never;
38 import static org.mockito.Mockito.reset;
39 import static org.mockito.Mockito.times;
40 import static org.mockito.Mockito.verify;
41 import static org.mockito.Mockito.when;
42 
43 import android.app.Activity;
44 import android.app.Instrumentation;
45 import android.app.KeyguardManager;
46 import android.app.Notification;
47 import android.app.NotificationManager;
48 import android.app.PendingIntent;
49 import android.content.Context;
50 import android.content.Intent;
51 import android.content.pm.ApplicationInfo;
52 import android.content.pm.PackageManager;
53 import android.content.res.Resources;
54 import android.net.NetworkCapabilities;
55 import android.net.NetworkInfo;
56 import android.os.Build;
57 import android.os.Bundle;
58 import android.os.PowerManager;
59 import android.os.UserHandle;
60 import android.telephony.TelephonyManager;
61 import android.testing.PollingCheck;
62 import android.util.DisplayMetrics;
63 import android.widget.TextView;
64 
65 import androidx.annotation.NonNull;
66 import androidx.annotation.Nullable;
67 import androidx.annotation.StringRes;
68 import androidx.test.filters.SmallTest;
69 import androidx.test.platform.app.InstrumentationRegistry;
70 import androidx.test.uiautomator.By;
71 import androidx.test.uiautomator.UiDevice;
72 import androidx.test.uiautomator.UiObject;
73 import androidx.test.uiautomator.UiSelector;
74 import androidx.test.uiautomator.Until;
75 
76 import com.android.connectivity.resources.R;
77 import com.android.modules.utils.build.SdkLevel;
78 import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
79 import com.android.testutils.DevSdkIgnoreRule;
80 import com.android.testutils.DevSdkIgnoreRunner;
81 
82 import org.junit.After;
83 import org.junit.Before;
84 import org.junit.Ignore;
85 import org.junit.Test;
86 import org.junit.runner.RunWith;
87 import org.mockito.AdditionalAnswers;
88 import org.mockito.ArgumentCaptor;
89 import org.mockito.Mock;
90 import org.mockito.MockitoAnnotations;
91 
92 import java.util.ArrayList;
93 import java.util.Arrays;
94 import java.util.Collections;
95 import java.util.List;
96 
97 @RunWith(DevSdkIgnoreRunner.class)
98 @SmallTest
99 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
100 public class NetworkNotificationManagerTest {
101 
102     private static final String TEST_SSID = "Test SSID";
103     private static final String TEST_EXTRA_INFO = "extra";
104     private static final int TEST_NOTIF_ID = 101;
105     private static final String TEST_NOTIF_TAG = NetworkNotificationManager.tagFor(TEST_NOTIF_ID);
106     private static final long TEST_TIMEOUT_MS = 10_000L;
107     private static final long UI_AUTOMATOR_WAIT_TIME_MILLIS = TEST_TIMEOUT_MS;
108 
109     static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
110     static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
111     static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
112     static {
113         CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
114         CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
115 
116         WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
117         WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
118         WIFI_CAPABILITIES.setSSID(TEST_SSID);
119 
120         // Set the underyling network to wifi.
121         VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
122         VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
123         VPN_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
124         VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
125     }
126 
127     /**
128      * Test activity that shows the action it was started with on screen, and dismisses when the
129      * text is tapped.
130      */
131     public static class TestDialogActivity extends Activity {
132         @Override
onCreate(@ullable Bundle savedInstanceState)133         protected void onCreate(@Nullable Bundle savedInstanceState) {
134             super.onCreate(savedInstanceState);
135             setTurnScreenOn(true);
136             getSystemService(KeyguardManager.class).requestDismissKeyguard(
137                     this, null /* callback */);
138 
139             final TextView txt = new TextView(this);
140             txt.setText(getIntent().getAction());
141             txt.setOnClickListener(e -> finish());
142             setContentView(txt);
143         }
144     }
145 
146     @Mock Context mCtx;
147     @Mock Resources mResources;
148     @Mock DisplayMetrics mDisplayMetrics;
149     @Mock PackageManager mPm;
150     @Mock TelephonyManager mTelephonyManager;
151     @Mock NotificationManager mNotificationManager;
152     @Mock NetworkAgentInfo mWifiNai;
153     @Mock NetworkAgentInfo mCellNai;
154     @Mock NetworkAgentInfo mVpnNai;
155     @Mock NetworkInfo mNetworkInfo;
156     ArgumentCaptor<Notification> mCaptor;
157 
158     NetworkNotificationManager mManager;
159 
160     @Before
setUp()161     public void setUp() {
162         MockitoAnnotations.initMocks(this);
163         mCaptor = ArgumentCaptor.forClass(Notification.class);
164         mWifiNai.networkCapabilities = WIFI_CAPABILITIES;
165         mWifiNai.networkInfo = mNetworkInfo;
166         mCellNai.networkCapabilities = CELL_CAPABILITIES;
167         mCellNai.networkInfo = mNetworkInfo;
168         mVpnNai.networkCapabilities = VPN_CAPABILITIES;
169         mVpnNai.networkInfo = mNetworkInfo;
170         mDisplayMetrics.density = 2.275f;
171         doReturn(true).when(mVpnNai).isVPN();
172         when(mCtx.getResources()).thenReturn(mResources);
173         when(mCtx.getPackageManager()).thenReturn(mPm);
174         when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
175         final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mCtx));
176         doReturn(UserHandle.ALL).when(asUserCtx).getUser();
177         when(mCtx.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
178         when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
179                 .thenReturn(mNotificationManager);
180         when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO);
181         ConnectivityResources.setResourcesContextForTest(mCtx);
182         when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
183         when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics);
184 
185         // Come up with some credible-looking transport names. The actual values do not matter.
186         String[] transportNames = new String[NetworkCapabilities.MAX_TRANSPORT + 1];
187         for (int transport = 0; transport <= NetworkCapabilities.MAX_TRANSPORT; transport++) {
188             transportNames[transport] = NetworkCapabilities.transportNameOf(transport);
189         }
190         when(mResources.getStringArray(R.array.network_switch_type_name))
191             .thenReturn(transportNames);
192         when(mResources.getBoolean(R.bool.config_autoCancelNetworkNotifications)).thenReturn(true);
193 
194         mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
195     }
196 
197     @After
tearDown()198     public void tearDown() {
199         ConnectivityResources.setResourcesContextForTest(null);
200     }
201 
verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title)202     private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
203         final String tag = NetworkNotificationManager.tagFor(id);
204         mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
205         verify(mNotificationManager, times(1))
206                 .notify(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any());
207         final int transportType = NetworkNotificationManager.approximateTransportType(nai);
208         if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
209             verify(mResources, times(1)).getString(eq(title), eq(TEST_EXTRA_INFO));
210         } else {
211             verify(mResources, times(1)).getString(title);
212         }
213         verify(mResources, times(1)).getString(eq(R.string.private_dns_broken_detailed));
214     }
215 
216     @Test
testTitleOfPrivateDnsBroken()217     public void testTitleOfPrivateDnsBroken() {
218         // Test the title of mobile data.
219         verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet);
220         clearInvocations(mResources);
221 
222         // Test the title of wifi.
223         verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet);
224         clearInvocations(mResources);
225 
226         // Test the title of other networks.
227         verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet);
228         clearInvocations(mResources);
229     }
230 
231     @Test
testNotificationsShownAndCleared()232     public void testNotificationsShownAndCleared() {
233         final int NETWORK_ID_BASE = 100;
234         List<NotificationType> types = Arrays.asList(NotificationType.values());
235         List<Integer> ids = new ArrayList<>(types.size());
236         for (int i = 0; i < types.size(); i++) {
237             ids.add(NETWORK_ID_BASE + i);
238         }
239         Collections.shuffle(ids);
240         Collections.shuffle(types);
241 
242         for (int i = 0; i < ids.size(); i++) {
243             mManager.showNotification(ids.get(i), types.get(i), mWifiNai, mCellNai, null, false);
244         }
245 
246         List<Integer> idsToClear = new ArrayList<>(ids);
247         Collections.shuffle(idsToClear);
248         for (int i = 0; i < ids.size(); i++) {
249             mManager.clearNotification(idsToClear.get(i));
250         }
251 
252         for (int i = 0; i < ids.size(); i++) {
253             final int id = ids.get(i);
254             final int eventId = types.get(i).eventId;
255             final String tag = NetworkNotificationManager.tagFor(id);
256             verify(mNotificationManager, times(1)).notify(eq(tag), eq(eventId), any());
257             verify(mNotificationManager, times(1)).cancel(eq(tag), eq(eventId));
258         }
259     }
260 
261     @Test
262     @Ignore
263     // Ignored because the code under test calls Log.wtf, which crashes the tests on eng builds.
264     // TODO: re-enable after fixing this (e.g., turn Log.wtf into exceptions that this test catches)
testNoInternetNotificationsNotShownForCellular()265     public void testNoInternetNotificationsNotShownForCellular() {
266         mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
267         mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
268 
269         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
270 
271         mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
272 
273         final int eventId = NO_INTERNET.eventId;
274         final String tag = NetworkNotificationManager.tagFor(102);
275         verify(mNotificationManager, times(1)).notify(eq(tag), eq(eventId), any());
276     }
277 
278     @Test
testNotificationsNotShownIfNoInternetCapability()279     public void testNotificationsNotShownIfNoInternetCapability() {
280         mWifiNai.networkCapabilities = new NetworkCapabilities();
281         mWifiNai.networkCapabilities .addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
282         mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
283         mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false);
284         mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
285 
286         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
287     }
288 
assertNotification(NotificationType type, boolean ongoing, boolean autoCancel)289     private void assertNotification(NotificationType type, boolean ongoing, boolean autoCancel) {
290         final ArgumentCaptor<Notification> noteCaptor = ArgumentCaptor.forClass(Notification.class);
291         mManager.showNotification(TEST_NOTIF_ID, type, mWifiNai, mCellNai, null, false);
292         verify(mNotificationManager, times(1)).notify(eq(TEST_NOTIF_TAG), eq(type.eventId),
293                 noteCaptor.capture());
294 
295         assertEquals("Notification ongoing flag should be " + (ongoing ? "set" : "unset"),
296                 ongoing, (noteCaptor.getValue().flags & FLAG_ONGOING_EVENT) != 0);
297         assertEquals("Notification autocancel flag should be " + (autoCancel ? "set" : "unset"),
298                 autoCancel, (noteCaptor.getValue().flags & FLAG_AUTO_CANCEL) != 0);
299     }
300 
301     @Test
testDuplicatedNotificationsNoInternetThenSignIn()302     public void testDuplicatedNotificationsNoInternetThenSignIn() {
303         // Show first NO_INTERNET
304         assertNotification(NO_INTERNET, false /* ongoing */, true /* autoCancel */);
305 
306         // Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
307         assertNotification(SIGN_IN, false /* ongoing */, true /* autoCancel */);
308         verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
309 
310         // Network disconnects
311         mManager.clearNotification(TEST_NOTIF_ID);
312         verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
313     }
314 
315     @Test
testOngoingSignInNotification()316     public void testOngoingSignInNotification() {
317         doReturn(true).when(mResources).getBoolean(R.bool.config_ongoingSignInNotification);
318 
319         // Show first NO_INTERNET
320         assertNotification(NO_INTERNET, false /* ongoing */, true /* autoCancel */);
321 
322         // Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
323         assertNotification(SIGN_IN, true /* ongoing */, true /* autoCancel */);
324         verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
325 
326         // Network disconnects
327         mManager.clearNotification(TEST_NOTIF_ID);
328         verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
329     }
330 
331     @Test
testNoAutoCancelNotification()332     public void testNoAutoCancelNotification() {
333         doReturn(false).when(mResources).getBoolean(R.bool.config_autoCancelNetworkNotifications);
334 
335         // Show NO_INTERNET, then SIGN_IN
336         assertNotification(NO_INTERNET, false /* ongoing */, false /* autoCancel */);
337         assertNotification(SIGN_IN, false /* ongoing */, false /* autoCancel */);
338         verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(NO_INTERNET.eventId));
339 
340         mManager.clearNotification(TEST_NOTIF_ID);
341         verify(mNotificationManager, times(1)).cancel(eq(TEST_NOTIF_TAG), eq(SIGN_IN.eventId));
342     }
343 
344     @Test
testDuplicatedNotificationsSignInThenNoInternet()345     public void testDuplicatedNotificationsSignInThenNoInternet() {
346         final int id = TEST_NOTIF_ID;
347         final String tag = TEST_NOTIF_TAG;
348 
349         // Show first SIGN_IN
350         mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
351         verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
352         reset(mNotificationManager);
353 
354         // NO_INTERNET arrives after, but is ignored.
355         mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
356         verify(mNotificationManager, never()).cancel(any(), anyInt());
357         verify(mNotificationManager, never()).notify(any(), anyInt(), any());
358 
359         // Network disconnects
360         mManager.clearNotification(id);
361         verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
362     }
363 
364     @Test
testClearNotificationByType()365     public void testClearNotificationByType() {
366         final int id = TEST_NOTIF_ID;
367         final String tag = TEST_NOTIF_TAG;
368 
369         // clearNotification(int id, NotificationType notifyType) will check if given type is equal
370         // to previous type or not. If they are equal then clear the notification; if they are not
371         // equal then return.
372         mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
373         verify(mNotificationManager, times(1)).notify(eq(tag), eq(NO_INTERNET.eventId), any());
374 
375         // Previous notification is NO_INTERNET and given type is NO_INTERNET too. The notification
376         // should be cleared.
377         mManager.clearNotification(id, NO_INTERNET);
378         verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
379 
380         // SIGN_IN is popped-up.
381         mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
382         verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
383 
384         // The notification type is not matching previous one, PARTIAL_CONNECTIVITY won't be
385         // cleared.
386         mManager.clearNotification(id, PARTIAL_CONNECTIVITY);
387         verify(mNotificationManager, never()).cancel(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId));
388     }
389 
390     private static final int EXPECT_DIALOG = 0;
391     private static final int EXPECT_NOTIFICATION = 1;
392     @Test
testNotifyNoInternet_asNotification_ActivelyPrefer()393     public void testNotifyNoInternet_asNotification_ActivelyPrefer() throws Exception {
394         doTestNotifyNotificationAsDialogWhenHighPriority(false /* notifyAsDialog */,
395                 true /* activelyPreferBadWifi */, NO_INTERNET, EXPECT_NOTIFICATION);
396     }
397 
398     @Test
testNotifyNoInternet_asNotification_NotActivelyPrefer()399     public void testNotifyNoInternet_asNotification_NotActivelyPrefer() throws Exception {
400         doTestNotifyNotificationAsDialogWhenHighPriority(false /* notifyAsDialog */,
401                 false /* activelyPreferBadWifi */, NO_INTERNET, EXPECT_NOTIFICATION);
402     }
403 
404     @Test
testNotifyNoInternet_asDialog_ActivelyPrefer()405     public void testNotifyNoInternet_asDialog_ActivelyPrefer() throws Exception {
406         doTestNotifyNotificationAsDialogWhenHighPriority(true /* notifyAsDialog */,
407                 true /* activelyPreferBadWifi */, NO_INTERNET, EXPECT_DIALOG);
408     }
409 
410     @Test
testNotifyNoInternet_asDialog_NotActivelyPrefer()411     public void testNotifyNoInternet_asDialog_NotActivelyPrefer() throws Exception {
412         doTestNotifyNotificationAsDialogWhenHighPriority(true /* notifyAsDialog */,
413                 false /* activelyPreferBadWifi */, NO_INTERNET, EXPECT_DIALOG);
414     }
415 
416     @Test
testNotifyLostInternet_asNotification_ActivelyPrefer()417     public void testNotifyLostInternet_asNotification_ActivelyPrefer() throws Exception {
418         doTestNotifyNotificationAsDialogWhenHighPriority(false /* notifyAsDialog */,
419                 true /* activelyPreferBadWifi */, LOST_INTERNET, EXPECT_NOTIFICATION);
420     }
421 
422     @Test
testNotifyLostInternet_asNotification_NotActivelyPrefer()423     public void testNotifyLostInternet_asNotification_NotActivelyPrefer() throws Exception {
424         doTestNotifyNotificationAsDialogWhenHighPriority(false /* notifyAsDialog */,
425                 false /* activelyPreferBadWifi */, LOST_INTERNET, EXPECT_NOTIFICATION);
426     }
427 
428     @Test
testNotifyLostInternet_asDialog_ActivelyPrefer()429     public void testNotifyLostInternet_asDialog_ActivelyPrefer() throws Exception {
430         doTestNotifyNotificationAsDialogWhenHighPriority(true /* notifyAsDialog */,
431                 true /* activelyPreferBadWifi */, LOST_INTERNET,
432                 SdkLevel.isAtLeastT() ? EXPECT_DIALOG : EXPECT_NOTIFICATION);
433     }
434 
435     @Test
testNotifyLostInternet_asDialog_NotActivelyPrefer()436     public void testNotifyLostInternet_asDialog_NotActivelyPrefer() throws Exception {
437         doTestNotifyNotificationAsDialogWhenHighPriority(true /* notifyAsDialog */,
438                 false /* activelyPreferBadWifi */, LOST_INTERNET,
439                 SdkLevel.isAtLeastU() ? EXPECT_DIALOG : EXPECT_NOTIFICATION);
440     }
441 
442     // Pass EXPECT_DIALOG or EXPECT_NOTIFICATION to |expectBehavior|
doTestNotifyNotificationAsDialogWhenHighPriority( final boolean notifyAsDialog, final boolean activelyPreferBadWifi, @NonNull final NotificationType notifType, final int expectBehavior)443     public void doTestNotifyNotificationAsDialogWhenHighPriority(
444             final boolean notifyAsDialog, final boolean activelyPreferBadWifi,
445             @NonNull final NotificationType notifType, final int expectBehavior) throws Exception {
446         doReturn(notifyAsDialog).when(mResources).getBoolean(
447                 R.bool.config_notifyNoInternetAsDialogWhenHighPriority);
448         doReturn(activelyPreferBadWifi ? 1 : 0).when(mResources).getInteger(
449                 R.integer.config_activelyPreferBadWifi);
450 
451         final Instrumentation instr = InstrumentationRegistry.getInstrumentation();
452         final UiDevice uiDevice =  UiDevice.getInstance(instr);
453         final Context ctx = instr.getContext();
454         final PowerManager pm = ctx.getSystemService(PowerManager.class);
455         // If the prio of this notif is < that of NETWORK_SWITCH, it's the lowest prio and
456         // therefore it can't be tested whether it cancels other lower-prio notifs.
457         final boolean isLowestPrioNotif = NetworkNotificationManager.priority(notifType)
458                 < NetworkNotificationManager.priority(NETWORK_SWITCH);
459 
460         // Wake up the device (it has no effect if the device is already awake).
461         uiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
462         uiDevice.executeShellCommand("wm dismiss-keyguard");
463         PollingCheck.check("Wait for the screen to be turned on failed, timeout=" + TEST_TIMEOUT_MS,
464                 TEST_TIMEOUT_MS, () -> pm.isInteractive());
465         uiDevice.pressHome();
466 
467         // UiDevice.getLauncherPackageName() requires the test manifest to have a <queries> tag for
468         // the launcher intent.
469         final String launcherPackageName = uiDevice.getLauncherPackageName();
470         assertTrue(String.format("Launcher (%s) is not shown", launcherPackageName),
471                 uiDevice.wait(Until.hasObject(By.pkg(launcherPackageName)),
472                         UI_AUTOMATOR_WAIT_TIME_MILLIS));
473 
474         if (!isLowestPrioNotif) {
475             mManager.showNotification(TEST_NOTIF_ID, NETWORK_SWITCH, mWifiNai, mCellNai,
476                     null, false);
477             // Non-"no internet" notifications are not affected
478             verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(NETWORK_SWITCH.eventId),
479                     any());
480         }
481 
482         final String testAction = "com.android.connectivity.coverage.TEST_DIALOG";
483         final Intent intent = new Intent(testAction)
484                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
485                 .setClassName(ctx.getPackageName(), TestDialogActivity.class.getName());
486         final PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0 /* requestCode */,
487                 intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
488 
489         mManager.showNotification(TEST_NOTIF_ID, notifType, mWifiNai, null /* switchToNai */,
490                 pendingIntent, true /* highPriority */);
491 
492         if (!isLowestPrioNotif) {
493             // Previous notifications are still dismissed
494             verify(mNotificationManager).cancel(TEST_NOTIF_TAG, NETWORK_SWITCH.eventId);
495         }
496 
497         if (expectBehavior == EXPECT_DIALOG) {
498             // Verify that the activity is shown (the activity shows the action on screen)
499             final UiObject actionText = uiDevice.findObject(new UiSelector().text(testAction));
500             assertTrue("Activity not shown", actionText.waitForExists(TEST_TIMEOUT_MS));
501 
502             // Tapping the text should dismiss the dialog
503             actionText.click();
504             assertTrue("Activity not dismissed", actionText.waitUntilGone(TEST_TIMEOUT_MS));
505 
506             // Verify that the notification was not posted
507             verify(mNotificationManager, never()).notify(any(), eq(notifType.eventId), any());
508         } else {
509             // Notification should have been posted, and will have overridden the previous
510             // one because it has the same id (hence no cancel).
511             verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(notifType.eventId), any());
512         }
513     }
514 
doNotificationTextTest(NotificationType type, @StringRes int expectedTitleRes, String expectedTitleArg, @StringRes int expectedContentRes)515     private void doNotificationTextTest(NotificationType type, @StringRes int expectedTitleRes,
516             String expectedTitleArg, @StringRes int expectedContentRes) {
517         final String expectedTitle = "title " + expectedTitleArg;
518         final String expectedContent = "expected content";
519         doReturn(expectedTitle).when(mResources).getString(expectedTitleRes, expectedTitleArg);
520         doReturn(expectedContent).when(mResources).getString(expectedContentRes);
521 
522         mManager.showNotification(TEST_NOTIF_ID, type, mWifiNai, mCellNai, null, false);
523         final ArgumentCaptor<Notification> notifCap = ArgumentCaptor.forClass(Notification.class);
524 
525         verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(type.eventId),
526                 notifCap.capture());
527         final Notification notif = notifCap.getValue();
528 
529         assertEquals(expectedTitle, notif.extras.getString(Notification.EXTRA_TITLE));
530         assertEquals(expectedContent, notif.extras.getString(Notification.EXTRA_TEXT));
531     }
532 
533     @Test
testNotificationText_NoInternet()534     public void testNotificationText_NoInternet() {
535         doNotificationTextTest(NO_INTERNET,
536                 R.string.wifi_no_internet, TEST_EXTRA_INFO,
537                 R.string.wifi_no_internet_detailed);
538     }
539 
540     @Test
testNotificationText_Partial()541     public void testNotificationText_Partial() {
542         doNotificationTextTest(PARTIAL_CONNECTIVITY,
543                 R.string.network_partial_connectivity, TEST_EXTRA_INFO,
544                 R.string.network_partial_connectivity_detailed);
545     }
546 
547     @Test
testNotificationText_PartialAsNoInternet()548     public void testNotificationText_PartialAsNoInternet() {
549         doReturn(true).when(mResources).getBoolean(
550                 R.bool.config_partialConnectivityNotifiedAsNoInternet);
551         doNotificationTextTest(PARTIAL_CONNECTIVITY,
552                 R.string.wifi_no_internet, TEST_EXTRA_INFO,
553                 R.string.wifi_no_internet_detailed);
554     }
555 }
556