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.systemui.statusbar; 18 19 import static android.print.PrintManager.PRINT_SPOOLER_PACKAGE_NAME; 20 21 import static junit.framework.Assert.assertEquals; 22 import static junit.framework.Assert.assertFalse; 23 import static junit.framework.Assert.assertNull; 24 import static junit.framework.Assert.assertTrue; 25 26 import static org.mockito.Mockito.any; 27 import static org.mockito.Mockito.anyBoolean; 28 import static org.mockito.Mockito.anyInt; 29 import static org.mockito.Mockito.anyString; 30 import static org.mockito.Mockito.eq; 31 import static org.mockito.Mockito.mock; 32 import static org.mockito.Mockito.never; 33 import static org.mockito.Mockito.times; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.when; 36 37 import android.app.INotificationManager; 38 import android.app.Notification; 39 import android.app.NotificationChannel; 40 import android.app.NotificationChannelGroup; 41 import android.app.NotificationManager; 42 import android.content.Intent; 43 import android.content.pm.ActivityInfo; 44 import android.content.pm.ApplicationInfo; 45 import android.content.pm.PackageInfo; 46 import android.content.pm.PackageManager; 47 import android.content.pm.ResolveInfo; 48 import android.graphics.drawable.Drawable; 49 import android.os.UserHandle; 50 import android.service.notification.StatusBarNotification; 51 import android.test.suitebuilder.annotation.SmallTest; 52 import android.testing.AndroidTestingRunner; 53 import android.testing.UiThreadTest; 54 import android.view.LayoutInflater; 55 import android.view.View; 56 import android.widget.ImageView; 57 import android.widget.Switch; 58 import android.widget.TextView; 59 60 import com.android.systemui.R; 61 import com.android.systemui.SysuiTestCase; 62 63 import org.junit.Before; 64 import org.junit.Test; 65 import org.junit.runner.RunWith; 66 import org.mockito.ArgumentCaptor; 67 68 import java.util.ArrayList; 69 import java.util.Arrays; 70 import java.util.Collections; 71 import java.util.List; 72 import java.util.concurrent.CountDownLatch; 73 74 @SmallTest 75 @RunWith(AndroidTestingRunner.class) 76 @UiThreadTest 77 public class NotificationInfoTest extends SysuiTestCase { 78 private static final String TEST_PACKAGE_NAME = "test_package"; 79 private static final String TEST_SYSTEM_PACKAGE_NAME = PRINT_SPOOLER_PACKAGE_NAME; 80 private static final int TEST_UID = 1; 81 private static final String TEST_CHANNEL = "test_channel"; 82 private static final String TEST_CHANNEL_NAME = "TEST CHANNEL NAME"; 83 84 private NotificationInfo mNotificationInfo; 85 private final INotificationManager mMockINotificationManager = mock(INotificationManager.class); 86 private final PackageManager mMockPackageManager = mock(PackageManager.class); 87 private NotificationChannel mNotificationChannel; 88 private NotificationChannel mDefaultNotificationChannel; 89 private StatusBarNotification mSbn; 90 91 @Before 92 public void setUp() throws Exception { 93 // Inflate the layout 94 final LayoutInflater layoutInflater = LayoutInflater.from(mContext); 95 mNotificationInfo = (NotificationInfo) layoutInflater.inflate(R.layout.notification_info, 96 null); 97 98 // PackageManager must return a packageInfo and applicationInfo. 99 final PackageInfo packageInfo = new PackageInfo(); 100 packageInfo.packageName = TEST_PACKAGE_NAME; 101 when(mMockPackageManager.getPackageInfo(eq(TEST_PACKAGE_NAME), anyInt())) 102 .thenReturn(packageInfo); 103 final ApplicationInfo applicationInfo = new ApplicationInfo(); 104 applicationInfo.uid = TEST_UID; // non-zero 105 when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn( 106 applicationInfo); 107 final PackageInfo systemPackageInfo = new PackageInfo(); 108 systemPackageInfo.packageName = TEST_SYSTEM_PACKAGE_NAME; 109 when(mMockPackageManager.getPackageInfo(eq(TEST_SYSTEM_PACKAGE_NAME), anyInt())) 110 .thenReturn(systemPackageInfo); 111 when(mMockPackageManager.getPackageInfo(eq("android"), anyInt())) 112 .thenReturn(packageInfo); 113 114 // Package has one channel by default. 115 when(mMockINotificationManager.getNumNotificationChannelsForPackage( 116 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(1); 117 118 // Some test channels. 119 mNotificationChannel = new NotificationChannel( 120 TEST_CHANNEL, TEST_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW); 121 mDefaultNotificationChannel = new NotificationChannel( 122 NotificationChannel.DEFAULT_CHANNEL_ID, TEST_CHANNEL_NAME, 123 NotificationManager.IMPORTANCE_LOW); 124 mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, 125 new Notification(), UserHandle.CURRENT, null, 0); 126 } 127 128 private CharSequence getStringById(int resId) { 129 return mContext.getString(resId); 130 } 131 132 private CharSequence getNumChannelsDescString(int numChannels) { 133 return String.format( 134 mContext.getResources().getQuantityString( 135 R.plurals.notification_num_channels_desc, numChannels), 136 numChannels); 137 } 138 139 private CharSequence getChannelsListDescString(NotificationChannel... channels) { 140 if (channels.length == 2) { 141 return mContext.getString(R.string.notification_channels_list_desc_2, 142 channels[0].getName(), channels[1].getName()); 143 } else { 144 final int numOthers = channels.length - 2; 145 return String.format( 146 mContext.getResources().getQuantityString( 147 R.plurals.notification_channels_list_desc_2_and_others, numOthers), 148 channels[0].getName(), channels[1].getName(), numOthers); 149 } 150 } 151 152 private CharSequence getNumChannelsString(int numChannels) { 153 return mContext.getString(R.string.notification_num_channels, numChannels); 154 } 155 156 @Test 157 public void testBindNotification_SetsTextApplicationName() throws Exception { 158 when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); 159 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 160 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 161 mNotificationChannel.getImportance(), mSbn, null, null, null, 162 null, null); 163 final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.pkgname); 164 assertTrue(textView.getText().toString().contains("App Name")); 165 } 166 167 @Test 168 public void testBindNotification_SetsPackageIcon() throws Exception { 169 final Drawable iconDrawable = mock(Drawable.class); 170 when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class))) 171 .thenReturn(iconDrawable); 172 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 173 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 174 mNotificationChannel.getImportance(), mSbn, null, null, null, 175 null, null); 176 final ImageView iconView = (ImageView) mNotificationInfo.findViewById(R.id.pkgicon); 177 assertEquals(iconDrawable, iconView.getDrawable()); 178 } 179 180 @Test 181 public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception { 182 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 183 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 184 mNotificationChannel.getImportance(), mSbn, null, null, null, 185 null, null); 186 final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name); 187 assertEquals(View.GONE, groupNameView.getVisibility()); 188 final TextView groupDividerView = 189 (TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider); 190 assertEquals(View.GONE, groupDividerView.getVisibility()); 191 } 192 193 @Test 194 public void testBindNotification_SetsGroupNameIfNonNull() throws Exception { 195 mNotificationChannel.setGroup("test_group_id"); 196 final NotificationChannelGroup notificationChannelGroup = 197 new NotificationChannelGroup("test_group_id", "Test Group Name"); 198 when(mMockINotificationManager.getNotificationChannelGroupForPackage( 199 eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID))) 200 .thenReturn(notificationChannelGroup); 201 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 202 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 203 mNotificationChannel.getImportance(), mSbn, null, null, null, 204 null, null); 205 final TextView groupNameView = (TextView) mNotificationInfo.findViewById(R.id.group_name); 206 assertEquals(View.VISIBLE, groupNameView.getVisibility()); 207 assertEquals("Test Group Name", groupNameView.getText()); 208 final TextView groupDividerView = 209 (TextView) mNotificationInfo.findViewById(R.id.pkg_group_divider); 210 assertEquals(View.VISIBLE, groupDividerView.getVisibility()); 211 } 212 213 @Test 214 public void testBindNotification_SetsTextChannelName() throws Exception { 215 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 216 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 217 mNotificationChannel.getImportance(), mSbn, null, null, null, 218 null, null); 219 final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name); 220 assertEquals(TEST_CHANNEL_NAME, textView.getText()); 221 } 222 223 @Test 224 public void testBindNotification_DefaultChannelDoesNotUseChannelName() throws Exception { 225 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 226 TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), 227 mNotificationChannel.getImportance(), mSbn, null, null, null, 228 null, null); 229 final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name); 230 assertEquals(mContext.getString(R.string.notification_header_default_channel), 231 textView.getText()); 232 } 233 234 @Test 235 public void testBindNotification_UnblockablePackageDoesNotUseChannelName() throws Exception { 236 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 237 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 238 mNotificationChannel.getImportance(), mSbn, null, null, null, 239 null, Collections.singleton(TEST_PACKAGE_NAME)); 240 final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name); 241 assertEquals(mContext.getString(R.string.notification_header_default_channel), 242 textView.getText()); 243 } 244 245 @Test 246 public void testBindNotification_DefaultChannelUsesNameWhenMoreThanOneChannelExists() 247 throws Exception { 248 when(mMockINotificationManager.getNumNotificationChannelsForPackage( 249 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2); 250 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 251 TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), 252 mNotificationChannel.getImportance(), mSbn, null, null, null, 253 null, null); 254 final TextView textView = (TextView) mNotificationInfo.findViewById(R.id.channel_name); 255 assertEquals(mDefaultNotificationChannel.getName(), textView.getText()); 256 } 257 258 @Test 259 public void testBindNotification_SetsOnClickListenerForSettings() throws Exception { 260 final CountDownLatch latch = new CountDownLatch(1); 261 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 262 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 263 mNotificationChannel.getImportance(), mSbn, 264 (View v, NotificationChannel c, int appUid) -> { 265 assertEquals(mNotificationChannel, c); 266 latch.countDown(); 267 }, null, null, null, null); 268 269 final TextView settingsButton = 270 (TextView) mNotificationInfo.findViewById(R.id.more_settings); 271 settingsButton.performClick(); 272 // Verify that listener was triggered. 273 assertEquals(0, latch.getCount()); 274 } 275 276 @Test 277 public void testBindNotification_SettingsButtonInvisibleWhenNoClickListener() throws Exception { 278 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 279 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 280 mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); 281 final TextView settingsButton = 282 (TextView) mNotificationInfo.findViewById(R.id.more_settings); 283 assertTrue(settingsButton.getVisibility() != View.VISIBLE); 284 } 285 286 @Test 287 public void testBindNotification_SettingsButtonReappersAfterSecondBind() throws Exception { 288 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 289 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 290 mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); 291 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 292 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 293 mNotificationChannel.getImportance(), mSbn, 294 (View v, NotificationChannel c, int appUid) -> {}, null, null, null, null); 295 final TextView settingsButton = 296 (TextView) mNotificationInfo.findViewById(R.id.more_settings); 297 assertEquals(View.VISIBLE, settingsButton.getVisibility()); 298 } 299 300 @Test 301 public void testOnClickListenerPassesNullChannelForBundle() throws Exception { 302 final CountDownLatch latch = new CountDownLatch(1); 303 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 304 TEST_PACKAGE_NAME, 305 Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), 306 mNotificationChannel.getImportance(), mSbn, 307 (View v, NotificationChannel c, int appUid) -> { 308 assertEquals(null, c); 309 latch.countDown(); 310 }, null, null, null, null); 311 312 final TextView settingsButton = 313 (TextView) mNotificationInfo.findViewById(R.id.more_settings); 314 settingsButton.performClick(); 315 // Verify that listener was triggered. 316 assertEquals(0, latch.getCount()); 317 } 318 319 @Test 320 public void testBindNotification_SettingsTextWithOneChannel() throws Exception { 321 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 322 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 323 mNotificationChannel.getImportance(), mSbn, 324 (View v, NotificationChannel c, int appUid) -> { 325 }, null, null, null, null); 326 final TextView settingsButton = 327 (TextView) mNotificationInfo.findViewById(R.id.more_settings); 328 assertEquals(getStringById(R.string.notification_more_settings), settingsButton.getText()); 329 } 330 331 @Test 332 public void testBindNotification_SettingsTextWithMultipleChannels() throws Exception { 333 when(mMockINotificationManager.getNumNotificationChannelsForPackage( 334 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2); 335 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 336 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 337 mNotificationChannel.getImportance(), mSbn, 338 (View v, NotificationChannel c, int appUid) -> { 339 }, null, null, null, null); 340 final TextView settingsButton = 341 (TextView) mNotificationInfo.findViewById(R.id.more_settings); 342 assertEquals(getStringById(R.string.notification_all_categories), settingsButton.getText()); 343 } 344 345 @Test 346 public void testBindNotification_SettingsTextWithMultipleChannelsForUnblockableApp() 347 throws Exception { 348 when(mMockINotificationManager.getNumNotificationChannelsForPackage( 349 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2); 350 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 351 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 352 mNotificationChannel.getImportance(), mSbn, 353 (View v, NotificationChannel c, int appUid) -> { 354 }, null, null, null, Collections.singleton(TEST_PACKAGE_NAME)); 355 final TextView settingsButton = 356 (TextView) mNotificationInfo.findViewById(R.id.more_settings); 357 assertEquals(getStringById(R.string.notification_more_settings), settingsButton.getText()); 358 } 359 360 @Test 361 public void testBindNotification_SetsOnClickListenerForDone() throws Exception { 362 final CountDownLatch latch = new CountDownLatch(1); 363 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 364 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 365 mNotificationChannel.getImportance(), mSbn, null, 366 null, (View v) -> { 367 latch.countDown(); 368 }, 369 null, null); 370 371 final TextView doneButton = (TextView) mNotificationInfo.findViewById(R.id.done); 372 doneButton.performClick(); 373 // Verify that listener was triggered. 374 assertEquals(0, latch.getCount()); 375 } 376 377 @Test 378 public void testBindNotification_NumChannelsTextHiddenWhenDefaultChannel() throws Exception { 379 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 380 TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), 381 mNotificationChannel.getImportance(), mSbn, null, null, 382 null, null, null); 383 final TextView numChannelsView = 384 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 385 assertEquals(View.INVISIBLE, numChannelsView.getVisibility()); 386 } 387 388 @Test 389 public void testBindNotification_NumChannelsTextDisplaysWhenMoreThanOneChannelExists() 390 throws Exception { 391 when(mMockINotificationManager.getNumNotificationChannelsForPackage( 392 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2); 393 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 394 TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), 395 mNotificationChannel.getImportance(), mSbn, null, null, 396 null, null, null); 397 final TextView numChannelsView = 398 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 399 assertEquals(numChannelsView.getVisibility(), View.VISIBLE); 400 assertEquals(getNumChannelsDescString(2), numChannelsView.getText()); 401 } 402 403 @Test 404 public void testBindNotification_NumChannelsTextDisplaysWhenNotDefaultChannel() 405 throws Exception { 406 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 407 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 408 mNotificationChannel.getImportance(), mSbn, null, null, null, 409 null, null); 410 final TextView numChannelsView = 411 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 412 assertEquals(numChannelsView.getVisibility(), View.VISIBLE); 413 assertEquals(getNumChannelsDescString(1), numChannelsView.getText()); 414 } 415 416 @Test 417 public void testBindNotification_NumChannelsTextScalesWithNumberOfChannels() 418 throws Exception { 419 when(mMockINotificationManager.getNumNotificationChannelsForPackage( 420 eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(2); 421 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 422 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 423 mNotificationChannel.getImportance(), mSbn, null, null, null, 424 null, null); 425 final TextView numChannelsView = 426 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 427 assertEquals(getNumChannelsDescString(2), numChannelsView.getText()); 428 } 429 430 @Test 431 @UiThreadTest 432 public void testBindNotification_NumChannelsTextListsChannelsWhenTwoInBundle() 433 throws Exception { 434 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 435 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), 436 mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); 437 final TextView numChannelsView = 438 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 439 assertEquals(getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel), 440 numChannelsView.getText()); 441 } 442 443 @Test 444 @UiThreadTest 445 public void testBindNotification_NumChannelsTextListsChannelsWhenThreeInBundle() 446 throws Exception { 447 NotificationChannel thirdChannel = new NotificationChannel( 448 "third_channel", "third_channel", NotificationManager.IMPORTANCE_LOW); 449 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 450 TEST_PACKAGE_NAME, 451 Arrays.asList(mNotificationChannel, mDefaultNotificationChannel, thirdChannel), 452 mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); 453 final TextView numChannelsView = 454 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 455 assertEquals( 456 getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel, 457 thirdChannel), 458 numChannelsView.getText()); 459 } 460 461 @Test 462 @UiThreadTest 463 public void testBindNotification_NumChannelsTextListsChannelsWhenFourInBundle() 464 throws Exception { 465 NotificationChannel thirdChannel = new NotificationChannel( 466 "third_channel", "third_channel", NotificationManager.IMPORTANCE_LOW); 467 NotificationChannel fourthChannel = new NotificationChannel( 468 "fourth_channel", "fourth_channel", NotificationManager.IMPORTANCE_LOW); 469 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 470 TEST_PACKAGE_NAME, 471 Arrays.asList(mNotificationChannel, mDefaultNotificationChannel, thirdChannel, 472 fourthChannel), mNotificationChannel.getImportance(), mSbn, null, null, 473 null, null, null); 474 final TextView numChannelsView = 475 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 476 assertEquals( 477 getChannelsListDescString(mNotificationChannel, mDefaultNotificationChannel, 478 thirdChannel, fourthChannel), 479 numChannelsView.getText()); 480 } 481 482 @Test 483 @UiThreadTest 484 public void testBindNotification_ChannelNameChangesWhenBundleFromDifferentChannels() 485 throws Exception { 486 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 487 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), 488 mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); 489 final TextView channelNameView = 490 (TextView) mNotificationInfo.findViewById(R.id.channel_name); 491 assertEquals(getNumChannelsString(2), channelNameView.getText()); 492 } 493 494 @Test 495 @UiThreadTest 496 public void testEnabledSwitchInvisibleIfBundleFromDifferentChannels() throws Exception { 497 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 498 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), 499 mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); 500 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 501 assertEquals(View.INVISIBLE, enabledSwitch.getVisibility()); 502 } 503 504 @Test 505 public void testbindNotification_ChannelDisabledTextGoneWhenNotDisabled() throws Exception { 506 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 507 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 508 mNotificationChannel.getImportance(), mSbn, null, null, null, null, null); 509 final TextView channelDisabledView = 510 (TextView) mNotificationInfo.findViewById(R.id.channel_disabled); 511 assertEquals(channelDisabledView.getVisibility(), View.GONE); 512 } 513 514 @Test 515 public void testbindNotification_ChannelDisabledTextVisibleWhenDisabled() throws Exception { 516 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE); 517 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 518 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 519 mNotificationChannel.getImportance(), mSbn, null, null, null, 520 null, null); 521 final TextView channelDisabledView = 522 (TextView) mNotificationInfo.findViewById(R.id.channel_disabled); 523 assertEquals(channelDisabledView.getVisibility(), View.VISIBLE); 524 // Replaces the numChannelsView 525 final TextView numChannelsView = 526 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 527 assertEquals(numChannelsView.getVisibility(), View.GONE); 528 } 529 530 @Test 531 public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception { 532 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 533 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 534 mNotificationChannel.getImportance(), mSbn, null, null, null, 535 null, Collections.singleton(TEST_PACKAGE_NAME)); 536 final TextView numChannelsView = 537 (TextView) mNotificationInfo.findViewById(R.id.num_channels_desc); 538 assertEquals(View.VISIBLE, numChannelsView.getVisibility()); 539 assertEquals(mContext.getString(R.string.notification_unblockable_desc), 540 numChannelsView.getText()); 541 } 542 543 @Test 544 @UiThreadTest 545 public void testBindNotification_ChannelDisabledTextShowsForDefaultChannel() 546 throws Exception { 547 mDefaultNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE); 548 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 549 TEST_PACKAGE_NAME, Arrays.asList(mDefaultNotificationChannel), 550 mDefaultNotificationChannel.getImportance(), mSbn, null, null, 551 null, null, null); 552 final TextView channelDisabledView = 553 (TextView) mNotificationInfo.findViewById(R.id.channel_disabled); 554 assertEquals(View.VISIBLE, channelDisabledView.getVisibility()); 555 } 556 557 @Test 558 public void testBindNotification_DoesNotUpdateNotificationChannel() throws Exception { 559 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 560 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 561 mNotificationChannel.getImportance(), mSbn, null, null, null, 562 null, null); 563 verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( 564 anyString(), eq(TEST_UID), any()); 565 } 566 567 @Test 568 public void testDoesNotUpdateNotificationChannelAfterImportanceChanged() throws Exception { 569 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 570 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 571 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 572 mNotificationChannel.getImportance(), mSbn, null, null, null, 573 null, null); 574 575 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 576 enabledSwitch.setChecked(false); 577 verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( 578 anyString(), eq(TEST_UID), any()); 579 } 580 581 @Test 582 public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnchanged() 583 throws Exception { 584 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 585 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 586 mNotificationChannel.getImportance(), mSbn, null, null, null, 587 null, null); 588 589 mNotificationInfo.handleCloseControls(true, false); 590 verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( 591 anyString(), eq(TEST_UID), any()); 592 } 593 594 @Test 595 public void testHandleCloseControls_DoesNotUpdateNotificationChannelIfUnspecified() 596 throws Exception { 597 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED); 598 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 599 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 600 mNotificationChannel.getImportance(), mSbn, null, null, null, 601 null, null); 602 603 mNotificationInfo.handleCloseControls(true, false); 604 verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( 605 anyString(), eq(TEST_UID), any()); 606 } 607 608 @Test 609 public void testEnabledSwitchOnByDefault() throws Exception { 610 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 611 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 612 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 613 mNotificationChannel.getImportance(), mSbn, null, null, null, 614 null, null); 615 616 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 617 assertTrue(enabledSwitch.isChecked()); 618 } 619 620 @Test 621 public void testEnabledButtonOffWhenAlreadyBanned() throws Exception { 622 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_NONE); 623 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 624 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 625 mNotificationChannel.getImportance(), mSbn, null, null, null, 626 null, null); 627 628 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 629 assertFalse(enabledSwitch.isChecked()); 630 } 631 632 @Test 633 public void testEnabledSwitchVisibleByDefault() throws Exception { 634 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 635 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 636 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 637 mNotificationChannel.getImportance(), mSbn, null, null, null, 638 null, null); 639 640 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 641 assertEquals(View.VISIBLE, enabledSwitch.getVisibility()); 642 } 643 644 @Test 645 public void testEnabledSwitchInvisibleIfNonBlockable() throws Exception { 646 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 647 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 648 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 649 mNotificationChannel.getImportance(), mSbn, null, null, null, 650 null, Collections.singleton(TEST_PACKAGE_NAME)); 651 652 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 653 assertEquals(View.INVISIBLE, enabledSwitch.getVisibility()); 654 } 655 656 @Test 657 public void testEnabledSwitchInvisibleIfNonBlockableSystemChannel() throws Exception { 658 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 659 mNotificationChannel.setBlockableSystem(false); 660 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 661 TEST_SYSTEM_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 662 mNotificationChannel.getImportance(), mSbn, null, null, null, 663 null, null); 664 665 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 666 assertEquals(View.INVISIBLE, enabledSwitch.getVisibility()); 667 } 668 669 @Test 670 public void testEnabledSwitchVisibleIfBlockableSystemChannel() throws Exception { 671 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 672 mNotificationChannel.setBlockableSystem(true); 673 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 674 TEST_SYSTEM_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 675 mNotificationChannel.getImportance(), mSbn, null, null, null, 676 null, null); 677 678 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 679 assertEquals(View.VISIBLE, enabledSwitch.getVisibility()); 680 } 681 682 @Test 683 public void testEnabledSwitchInvisibleIfMultiChannelSummary() throws Exception { 684 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 685 mNotificationChannel.setBlockableSystem(true); 686 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 687 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), 688 mNotificationChannel.getImportance(), mSbn, null, null, null, 689 null, Collections.singleton(TEST_PACKAGE_NAME)); 690 691 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 692 assertEquals(View.INVISIBLE, enabledSwitch.getVisibility()); 693 } 694 695 @Test 696 public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception { 697 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 698 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 699 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 700 mNotificationChannel.getImportance(), mSbn, null, null, null, 701 null, Collections.singleton(TEST_PACKAGE_NAME)); 702 mNotificationInfo.handleCloseControls(true, false); 703 verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( 704 anyString(), eq(TEST_UID), any()); 705 } 706 707 @Test 708 public void testEnabledSwitchChangedCallsUpdateNotificationChannel() throws Exception { 709 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 710 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 711 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 712 mNotificationChannel.getImportance(), mSbn, null, null, null, 713 null, Collections.singleton(TEST_PACKAGE_NAME)); 714 715 Switch enabledSwitch = mNotificationInfo.findViewById(R.id.channel_enabled_switch); 716 enabledSwitch.setChecked(false); 717 mNotificationInfo.handleCloseControls(true, false); 718 719 ArgumentCaptor<NotificationChannel> updated = 720 ArgumentCaptor.forClass(NotificationChannel.class); 721 verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( 722 anyString(), eq(TEST_UID), updated.capture()); 723 assertTrue((updated.getValue().getUserLockedFields() 724 & NotificationChannel.USER_LOCKED_IMPORTANCE) != 0); 725 } 726 727 @Test 728 public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception { 729 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 730 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 731 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 732 mNotificationChannel.getImportance(), mSbn, null, null, null, 733 null, Collections.singleton(TEST_PACKAGE_NAME)); 734 735 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 736 enabledSwitch.setChecked(false); 737 mNotificationInfo.handleCloseControls(false, false); 738 verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( 739 eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel)); 740 } 741 742 @Test 743 public void testCloseControlsDoesNotUpdateIfCheckSaveListenerIsNoOp() throws Exception { 744 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 745 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 746 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 747 mNotificationChannel.getImportance(), mSbn, null, null, null, 748 (Runnable saveImportance) -> { 749 }, 750 Collections.singleton(TEST_PACKAGE_NAME)); 751 752 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 753 enabledSwitch.setChecked(false); 754 mNotificationInfo.handleCloseControls(true, false); 755 verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( 756 eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel)); 757 } 758 759 @Test 760 public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception { 761 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 762 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 763 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 764 mNotificationChannel.getImportance(), mSbn, null, null, null, 765 (Runnable saveImportance) -> { 766 saveImportance.run(); 767 }, 768 Collections.singleton(TEST_PACKAGE_NAME)); 769 770 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 771 enabledSwitch.setChecked(false); 772 mNotificationInfo.handleCloseControls(true, false); 773 verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage( 774 eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel)); 775 } 776 777 @Test 778 public void testDisplaySettingsLink() throws Exception { 779 final CountDownLatch latch = new CountDownLatch(1); 780 final String settingsText = "work chats"; 781 final ResolveInfo ri = new ResolveInfo(); 782 ri.activityInfo = new ActivityInfo(); 783 ri.activityInfo.packageName = TEST_PACKAGE_NAME; 784 ri.activityInfo.name = "something"; 785 List<ResolveInfo> ris = new ArrayList<>(); 786 ris.add(ri); 787 when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris); 788 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 789 Notification n = new Notification.Builder(mContext, mNotificationChannel.getId()) 790 .setSettingsText(settingsText).build(); 791 StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 792 0, null, 0, 0, n, UserHandle.CURRENT, null, 0); 793 794 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 795 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 796 mNotificationChannel.getImportance(), sbn, null, 797 (View v, Intent intent) -> { 798 latch.countDown(); 799 }, null, null, null); 800 final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); 801 assertEquals(View.VISIBLE, settingsLink.getVisibility()); 802 assertTrue(settingsLink.getText().toString().length() > settingsText.length()); 803 assertTrue(settingsLink.getText().toString().contains(settingsText)); 804 settingsLink.performClick(); 805 assertEquals(0, latch.getCount()); 806 } 807 808 @Test 809 public void testDisplaySettingsLink_multipleChannels() throws Exception { 810 final CountDownLatch latch = new CountDownLatch(1); 811 final String settingsText = "work chats"; 812 final ResolveInfo ri = new ResolveInfo(); 813 ri.activityInfo = new ActivityInfo(); 814 ri.activityInfo.packageName = TEST_PACKAGE_NAME; 815 ri.activityInfo.name = "something"; 816 List<ResolveInfo> ris = new ArrayList<>(); 817 ris.add(ri); 818 when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris); 819 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 820 Notification n = new Notification.Builder(mContext, mNotificationChannel.getId()) 821 .setSettingsText(settingsText).build(); 822 StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 823 0, null, 0, 0, n, UserHandle.CURRENT, null, 0); 824 825 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 826 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel, mDefaultNotificationChannel), 827 mNotificationChannel.getImportance(), sbn, null, (View v, Intent intent) -> { 828 latch.countDown(); 829 }, null, null, null); 830 final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); 831 assertEquals(View.VISIBLE, settingsLink.getVisibility()); 832 settingsLink.performClick(); 833 assertEquals(0, latch.getCount()); 834 } 835 836 @Test 837 public void testNoSettingsLink_noHandlingActivity() throws Exception { 838 final String settingsText = "work chats"; 839 when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(null); 840 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 841 Notification n = new Notification.Builder(mContext, mNotificationChannel.getId()) 842 .setSettingsText(settingsText).build(); 843 StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 844 0, null, 0, 0, n, UserHandle.CURRENT, null, 0); 845 846 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 847 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 848 mNotificationChannel.getImportance(), sbn, null, null, null, 849 null, null); 850 final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); 851 assertEquals(View.GONE, settingsLink.getVisibility()); 852 } 853 854 @Test 855 public void testNoSettingsLink_noLinkText() throws Exception { 856 final ResolveInfo ri = new ResolveInfo(); 857 ri.activityInfo = new ActivityInfo(); 858 ri.activityInfo.packageName = TEST_PACKAGE_NAME; 859 ri.activityInfo.name = "something"; 860 List<ResolveInfo> ris = new ArrayList<>(); 861 ris.add(ri); 862 when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris); 863 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 864 Notification n = new Notification.Builder(mContext, mNotificationChannel.getId()).build(); 865 StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 866 0, null, 0, 0, n, UserHandle.CURRENT, null, 0); 867 868 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 869 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 870 mNotificationChannel.getImportance(), sbn, null, null, null, 871 null, null); 872 final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); 873 assertEquals(View.GONE, settingsLink.getVisibility()); 874 } 875 876 @Test 877 public void testNoSettingsLink_afterBlockingChannel() throws Exception { 878 final String settingsText = "work chats"; 879 final ResolveInfo ri = new ResolveInfo(); 880 ri.activityInfo = new ActivityInfo(); 881 ri.activityInfo.packageName = TEST_PACKAGE_NAME; 882 ri.activityInfo.name = "something"; 883 List<ResolveInfo> ris = new ArrayList<>(); 884 ris.add(ri); 885 when(mMockPackageManager.queryIntentActivities(any(), anyInt())).thenReturn(ris); 886 mNotificationChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 887 Notification n = new Notification.Builder(mContext, mNotificationChannel.getId()) 888 .setSettingsText(settingsText).build(); 889 StatusBarNotification sbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 890 0, null, 0, 0, n, UserHandle.CURRENT, null, 0); 891 892 mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, 893 TEST_PACKAGE_NAME, Arrays.asList(mNotificationChannel), 894 mNotificationChannel.getImportance(), sbn, null, null, null, 895 null, null); 896 final TextView settingsLink = mNotificationInfo.findViewById(R.id.app_settings); 897 assertEquals(View.VISIBLE, settingsLink.getVisibility()); 898 899 // Block channel 900 Switch enabledSwitch = (Switch) mNotificationInfo.findViewById(R.id.channel_enabled_switch); 901 enabledSwitch.setChecked(false); 902 903 assertEquals(View.GONE, settingsLink.getVisibility()); 904 905 //unblock 906 enabledSwitch.setChecked(true); 907 assertEquals(View.VISIBLE, settingsLink.getVisibility()); 908 } 909 910 @Test 911 public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception { 912 assertFalse(mNotificationInfo.willBeRemoved()); 913 } 914 } 915