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