1 /* 2 * Copyright (C) 2020 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.people.widget; 18 19 import static android.app.Notification.CATEGORY_MISSED_CALL; 20 import static android.app.Notification.EXTRA_PEOPLE_LIST; 21 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 22 import static android.app.NotificationManager.IMPORTANCE_HIGH; 23 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS; 24 import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL; 25 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; 26 import static android.app.NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT; 27 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 28 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; 29 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 30 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 31 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 32 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 33 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 34 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 35 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 36 import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY; 37 import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY; 38 import static android.app.people.ConversationStatus.ACTIVITY_GAME; 39 import static android.app.people.PeopleSpaceTile.BLOCK_CONVERSATIONS; 40 import static android.app.people.PeopleSpaceTile.SHOW_CONTACTS; 41 import static android.app.people.PeopleSpaceTile.SHOW_CONVERSATIONS; 42 import static android.app.people.PeopleSpaceTile.SHOW_IMPORTANT_CONVERSATIONS; 43 import static android.app.people.PeopleSpaceTile.SHOW_STARRED_CONTACTS; 44 import static android.content.Intent.ACTION_BOOT_COMPLETED; 45 import static android.content.Intent.ACTION_PACKAGES_SUSPENDED; 46 import static android.content.Intent.ACTION_PACKAGE_REMOVED; 47 import static android.content.PermissionChecker.PERMISSION_GRANTED; 48 import static android.content.PermissionChecker.PERMISSION_HARD_DENIED; 49 import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE; 50 51 import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING; 52 import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID; 53 import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; 54 import static com.android.systemui.people.PeopleSpaceUtils.USER_ID; 55 56 import static com.google.common.truth.Truth.assertThat; 57 58 import static org.mockito.ArgumentMatchers.any; 59 import static org.mockito.ArgumentMatchers.anyBoolean; 60 import static org.mockito.ArgumentMatchers.anyInt; 61 import static org.mockito.ArgumentMatchers.anyString; 62 import static org.mockito.ArgumentMatchers.eq; 63 import static org.mockito.Mockito.mock; 64 import static org.mockito.Mockito.never; 65 import static org.mockito.Mockito.times; 66 import static org.mockito.Mockito.verify; 67 import static org.mockito.Mockito.when; 68 69 import static java.util.Objects.requireNonNull; 70 71 import android.app.INotificationManager; 72 import android.app.Notification; 73 import android.app.NotificationChannel; 74 import android.app.NotificationManager; 75 import android.app.Person; 76 import android.app.backup.BackupManager; 77 import android.app.people.ConversationChannel; 78 import android.app.people.ConversationStatus; 79 import android.app.people.IPeopleManager; 80 import android.app.people.PeopleManager; 81 import android.app.people.PeopleSpaceTile; 82 import android.appwidget.AppWidgetManager; 83 import android.appwidget.AppWidgetProviderInfo; 84 import android.content.ComponentName; 85 import android.content.Context; 86 import android.content.Intent; 87 import android.content.SharedPreferences; 88 import android.content.pm.LauncherApps; 89 import android.content.pm.PackageManager; 90 import android.content.pm.ParceledListSlice; 91 import android.content.pm.ShortcutInfo; 92 import android.graphics.drawable.Icon; 93 import android.net.Uri; 94 import android.os.Bundle; 95 import android.os.UserHandle; 96 import android.os.UserManager; 97 import android.platform.test.annotations.DisableFlags; 98 import android.platform.test.annotations.EnableFlags; 99 import android.service.notification.ConversationChannelWrapper; 100 import android.service.notification.StatusBarNotification; 101 import android.service.notification.ZenModeConfig; 102 import android.text.TextUtils; 103 104 import androidx.preference.PreferenceManager; 105 import androidx.test.ext.junit.runners.AndroidJUnit4; 106 import androidx.test.filters.SmallTest; 107 108 import com.android.systemui.SysuiTestCase; 109 import com.android.systemui.people.PeopleBackupFollowUpJob; 110 import com.android.systemui.people.PeopleSpaceUtils; 111 import com.android.systemui.people.SharedPreferencesHelper; 112 import com.android.systemui.res.R; 113 import com.android.systemui.settings.FakeUserTracker; 114 import com.android.systemui.statusbar.NotificationListener; 115 import com.android.systemui.statusbar.NotificationListener.NotificationHandler; 116 import com.android.systemui.statusbar.SbnBuilder; 117 import com.android.systemui.statusbar.notification.collection.NoManSimulator; 118 import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent; 119 import com.android.systemui.statusbar.notification.collection.NotificationEntry; 120 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; 121 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; 122 import com.android.systemui.util.concurrency.FakeExecutor; 123 import com.android.systemui.util.time.FakeSystemClock; 124 import com.android.wm.shell.bubbles.Bubbles; 125 126 import org.junit.Before; 127 import org.junit.Test; 128 import org.junit.runner.RunWith; 129 import org.mockito.ArgumentCaptor; 130 import org.mockito.Captor; 131 import org.mockito.Mock; 132 import org.mockito.MockitoAnnotations; 133 134 import java.lang.reflect.Field; 135 import java.util.ArrayList; 136 import java.util.Arrays; 137 import java.util.Collections; 138 import java.util.HashSet; 139 import java.util.List; 140 import java.util.Map; 141 import java.util.Optional; 142 import java.util.Set; 143 import java.util.stream.Collectors; 144 145 @SmallTest 146 @RunWith(AndroidJUnit4.class) 147 public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { 148 private static final long MIN_LINGER_DURATION = 5; 149 150 private static final String TEST_PACKAGE_A = "com.android.systemui.tests"; 151 private static final String TEST_PACKAGE_B = "com.test.package_b"; 152 private static final String TEST_PACKAGE_C = "com.test.package_c"; 153 private static final String TEST_CHANNEL_ID = "channel_id"; 154 private static final String TEST_CHANNEL_NAME = "channel_name"; 155 private static final String TEST_PARENT_CHANNEL_ID = "parent_channel_id"; 156 private static final String TEST_CONVERSATION_ID = "conversation_id"; 157 private static final int WIDGET_ID_WITH_SHORTCUT = 1; 158 private static final int SECOND_WIDGET_ID_WITH_SHORTCUT = 3; 159 private static final int WIDGET_ID_WITHOUT_SHORTCUT = 2; 160 private static final int WIDGET_ID_WITH_KEY_IN_OPTIONS = 4; 161 private static final int WIDGET_ID_WITH_SAME_URI = 5; 162 private static final int WIDGET_ID_WITH_DIFFERENT_URI = 6; 163 private static final int WIDGET_ID_8 = 8; 164 private static final int WIDGET_ID_9 = 9; 165 private static final int WIDGET_ID_11 = 11; 166 private static final int WIDGET_ID_14 = 14; 167 private static final int WIDGET_ID_15 = 15; 168 private static final String SHORTCUT_ID = "101"; 169 private static final String OTHER_SHORTCUT_ID = "102"; 170 private static final String THIRD_SHORTCUT_ID = "103"; 171 private static final String NOTIFICATION_KEY = "0|com.android.systemui.tests|0|null|0"; 172 private static final String NOTIFICATION_CONTENT_1 = "message text 1"; 173 private static final Uri URI = Uri.parse("fake_uri"); 174 private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android); 175 private static final PeopleTileKey KEY = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); 176 private static final Person PERSON = new Person.Builder() 177 .setName("name") 178 .setKey("abc") 179 .setUri(URI.toString()) 180 .setBot(false) 181 .build(); 182 private static final PeopleSpaceTile PERSON_TILE = 183 new PeopleSpaceTile 184 .Builder(SHORTCUT_ID, "username", ICON, new Intent()) 185 .setPackageName(TEST_PACKAGE_A) 186 .setUserHandle(new UserHandle(0)) 187 .setNotificationKey(NOTIFICATION_KEY + "1") 188 .setNotificationContent(NOTIFICATION_CONTENT_1) 189 .setNotificationDataUri(URI) 190 .setContactUri(URI) 191 .build(); 192 private static final PeopleSpaceTile PERSON_TILE_WITH_SAME_URI = 193 new PeopleSpaceTile 194 // Different shortcut ID 195 .Builder(OTHER_SHORTCUT_ID, "username", ICON, new Intent()) 196 // Different package name 197 .setPackageName(TEST_PACKAGE_B) 198 .setUserHandle(new UserHandle(0)) 199 // Same contact uri. 200 .setContactUri(URI) 201 .build(); 202 private static final int ALL_SUPPRESSED_VISUAL_EFFECTS = SUPPRESSED_EFFECT_SCREEN_OFF 203 | SUPPRESSED_EFFECT_SCREEN_ON 204 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT 205 | SUPPRESSED_EFFECT_AMBIENT 206 | SUPPRESSED_EFFECT_STATUS_BAR 207 | SUPPRESSED_EFFECT_BADGE 208 | SUPPRESSED_EFFECT_LIGHTS 209 | SUPPRESSED_EFFECT_PEEK 210 | SUPPRESSED_EFFECT_NOTIFICATION_LIST; 211 private static final long SBN_POST_TIME = 567L; 212 213 private static final Map<String, String> WIDGETS_MAPPING = Map.of( 214 String.valueOf(WIDGET_ID_8), String.valueOf(WIDGET_ID_WITH_SHORTCUT), 215 String.valueOf(WIDGET_ID_9), String.valueOf(WIDGET_ID_WITHOUT_SHORTCUT), 216 String.valueOf(WIDGET_ID_11), String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS), 217 String.valueOf(WIDGET_ID_14), String.valueOf(WIDGET_ID_WITH_SAME_URI), 218 String.valueOf(WIDGET_ID_15), String.valueOf(WIDGET_ID_WITH_DIFFERENT_URI) 219 ); 220 221 private static final Map<String, String> WIDGETS_MAPPING_CROSS_MAPPING = Map.of( 222 String.valueOf(WIDGET_ID_WITH_SHORTCUT), String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS), 223 String.valueOf(WIDGET_ID_WITHOUT_SHORTCUT), String.valueOf(WIDGET_ID_WITHOUT_SHORTCUT), 224 String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS), String.valueOf(WIDGET_ID_WITH_SHORTCUT) 225 ); 226 227 private ShortcutInfo mShortcutInfo; 228 private NotificationEntry mNotificationEntry; 229 230 private PeopleSpaceWidgetManager mManager; 231 232 @Mock 233 private Context mMockContext; 234 235 @Mock 236 private NotificationListener mListenerService; 237 238 @Mock 239 private AppWidgetManager mAppWidgetManager; 240 @Mock 241 private IPeopleManager mIPeopleManager; 242 @Mock 243 private PeopleManager mPeopleManager; 244 @Mock 245 private LauncherApps mLauncherApps; 246 @Mock 247 private CommonNotifCollection mNotifCollection; 248 @Mock 249 private PackageManager mPackageManager; 250 @Mock 251 private INotificationManager mINotificationManager; 252 @Mock 253 private UserManager mUserManager; 254 @Mock 255 private NotificationManager mNotificationManager; 256 @Mock 257 private NotificationManager.Policy mNotificationPolicy; 258 @Mock 259 private Bubbles mBubbles; 260 @Mock 261 private BackupManager mBackupManager; 262 263 @Captor 264 private ArgumentCaptor<NotificationHandler> mListenerCaptor; 265 @Captor 266 private ArgumentCaptor<Bundle> mBundleArgumentCaptor; 267 268 private final NoManSimulator mNoMan = new NoManSimulator(); 269 private final FakeSystemClock mClock = new FakeSystemClock(); 270 271 private final FakeExecutor mFakeExecutor = new FakeExecutor(mClock); 272 273 private final FakeUserTracker mUserTracker = new FakeUserTracker(); 274 275 @Before setUp()276 public void setUp() throws Exception { 277 MockitoAnnotations.initMocks(this); 278 mLauncherApps = mock(LauncherApps.class); 279 mManager = new PeopleSpaceWidgetManager(mContext, mAppWidgetManager, mIPeopleManager, 280 mPeopleManager, mLauncherApps, mNotifCollection, mPackageManager, 281 Optional.of(mBubbles), mUserManager, mBackupManager, mINotificationManager, 282 mNotificationManager, mFakeExecutor, mUserTracker); 283 mManager.attach(mListenerService); 284 285 verify(mListenerService).addNotificationHandler(mListenerCaptor.capture()); 286 NotificationHandler serviceListener = requireNonNull(mListenerCaptor.getValue()); 287 mNoMan.addListener(serviceListener); 288 289 clearStorage(); 290 addTileForWidget(PERSON_TILE, WIDGET_ID_WITH_SHORTCUT); 291 addTileForWidget(PERSON_TILE_WITH_SAME_URI, WIDGET_ID_WITH_SAME_URI); 292 when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT))) 293 .thenReturn(new Bundle()); 294 295 when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); 296 when(mPackageManager.isPackageSuspended(any())).thenReturn(false); 297 setFinalField("suppressedVisualEffects", ALL_SUPPRESSED_VISUAL_EFFECTS); 298 when(mNotificationPolicy.allowConversationsFrom()).thenReturn(CONVERSATION_SENDERS_ANYONE); 299 when(mNotificationPolicy.allowConversations()).thenReturn(false); 300 when(mNotificationPolicy.allowMessagesFrom()).thenReturn(ZenModeConfig.SOURCE_ANYONE); 301 when(mNotificationPolicy.allowMessages()).thenReturn(false); 302 when(mNotificationManager.getNotificationPolicy()).thenReturn(mNotificationPolicy); 303 when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( 304 INTERRUPTION_FILTER_ALL); 305 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; 306 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 307 when(mBubbles.isBubbleNotificationSuppressedFromShade(any(), any())).thenReturn(false); 308 309 when(mMockContext.getPackageName()).thenReturn(TEST_PACKAGE_A); 310 when(mMockContext.getUserId()).thenReturn(0); 311 mShortcutInfo = new ShortcutInfo.Builder(mMockContext, 312 SHORTCUT_ID).setLongLabel("name").build(); 313 mNotificationEntry = new NotificationEntryBuilder() 314 .setSbn(createNotification( 315 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false)) 316 .setId(1) 317 .setShortcutInfo(mShortcutInfo) 318 .build(); 319 320 AppWidgetProviderInfo providerInfo = new AppWidgetProviderInfo(); 321 providerInfo.provider = new ComponentName("com.android.systemui.tests", 322 "com.android.systemui.people.widget.PeopleSpaceWidgetProvider"); 323 when(mAppWidgetManager.getInstalledProvidersForPackage(anyString(), any())) 324 .thenReturn(List.of(providerInfo)); 325 } 326 327 @Test testGetRecentTilesReturnsSortedListWithOnlyRecentConversations()328 public void testGetRecentTilesReturnsSortedListWithOnlyRecentConversations() throws Exception { 329 // Ensure the less-recent Important conversation is before more recent conversations. 330 ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper( 331 SHORTCUT_ID, false, 3); 332 ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper( 333 SHORTCUT_ID + 1, true, 3); 334 ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper( 335 SHORTCUT_ID + 2, 336 true, 1); 337 when(mINotificationManager.getConversations(anyBoolean())).thenReturn( 338 new ParceledListSlice(Arrays.asList( 339 newerNonImportantConversation, newerImportantConversation, 340 olderImportantConversation))); 341 342 // Ensure the non-Important conversation is sorted between these recent conversations. 343 ConversationChannel recentConversationBeforeNonImportantConversation = 344 getConversationChannel( 345 SHORTCUT_ID + 3, 4); 346 ConversationChannel recentConversationAfterNonImportantConversation = 347 getConversationChannel(SHORTCUT_ID + 4, 348 2); 349 when(mIPeopleManager.getRecentConversations()).thenReturn( 350 new ParceledListSlice(Arrays.asList(recentConversationAfterNonImportantConversation, 351 recentConversationBeforeNonImportantConversation))); 352 353 List<String> orderedShortcutIds = mManager.getRecentTiles() 354 .stream().map(tile -> tile.getId()).collect(Collectors.toList()); 355 356 // Check for sorted recent conversations. 357 assertThat(orderedShortcutIds).containsExactly( 358 recentConversationBeforeNonImportantConversation.getShortcutInfo().getId(), 359 newerNonImportantConversation.getShortcutInfo().getId(), 360 recentConversationAfterNonImportantConversation.getShortcutInfo().getId()) 361 .inOrder(); 362 } 363 364 @Test testGetPriorityTilesReturnsSortedListWithOnlyImportantConversations()365 public void testGetPriorityTilesReturnsSortedListWithOnlyImportantConversations() 366 throws Exception { 367 // Ensure the less-recent Important conversation is before more recent conversations. 368 ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper( 369 SHORTCUT_ID, false, 3); 370 ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper( 371 SHORTCUT_ID + 1, true, 3); 372 ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper( 373 SHORTCUT_ID + 2, 374 true, 1); 375 when(mINotificationManager.getConversations(anyBoolean())).thenReturn( 376 new ParceledListSlice(Arrays.asList( 377 newerNonImportantConversation, newerImportantConversation, 378 olderImportantConversation))); 379 380 List<String> orderedShortcutIds = mManager.getPriorityTiles() 381 .stream().map(tile -> tile.getId()).collect(Collectors.toList()); 382 383 // Check for sorted priority conversations. 384 assertThat(orderedShortcutIds).containsExactly( 385 newerImportantConversation.getShortcutInfo().getId(), 386 olderImportantConversation.getShortcutInfo().getId()) 387 .inOrder(); 388 } 389 390 @Test testGetTilesReturnsNothingInQuietMode()391 public void testGetTilesReturnsNothingInQuietMode() 392 throws Exception { 393 // Ensure the less-recent Important conversation is before more recent conversations. 394 ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper( 395 SHORTCUT_ID, false, 3); 396 ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper( 397 SHORTCUT_ID + 1, true, 3); 398 ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper( 399 SHORTCUT_ID + 2, 400 true, 1); 401 when(mINotificationManager.getConversations(anyBoolean())).thenReturn( 402 new ParceledListSlice(Arrays.asList( 403 newerNonImportantConversation, newerImportantConversation, 404 olderImportantConversation))); 405 ConversationChannel recentConversation = 406 getConversationChannel( 407 SHORTCUT_ID + 3, 4); 408 when(mIPeopleManager.getRecentConversations()).thenReturn( 409 new ParceledListSlice(Arrays.asList(recentConversation))); 410 411 when(mUserManager.isQuietModeEnabled(any())).thenReturn(true); 412 413 // Check nothing returned. 414 assertThat(mManager.getPriorityTiles()).isEmpty(); 415 assertThat(mManager.getRecentTiles()).isEmpty(); 416 } 417 418 @Test testDoNotUpdateAppWidgetIfNoWidgets()419 public void testDoNotUpdateAppWidgetIfNoWidgets() throws Exception { 420 int[] widgetIdsArray = {}; 421 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 422 423 StatusBarNotification sbn = createNotification( 424 OTHER_SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ false); 425 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 426 .setSbn(sbn) 427 .setId(1)); 428 mClock.advanceTime(MIN_LINGER_DURATION); 429 430 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 431 any()); 432 } 433 434 @Test testDoNotUpdateAppWidgetIfNoShortcutInfo()435 public void testDoNotUpdateAppWidgetIfNoShortcutInfo() throws Exception { 436 int[] widgetIdsArray = {}; 437 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 438 439 Notification notificationWithoutShortcut = new Notification.Builder(mContext) 440 .setContentTitle("TEST_TITLE") 441 .setContentText("TEST_TEXT") 442 .setStyle(new Notification.MessagingStyle(PERSON) 443 .addMessage(new Notification.MessagingStyle.Message("text3", 10, PERSON)) 444 ) 445 .build(); 446 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 447 .setSbn(new SbnBuilder() 448 .setNotification(notificationWithoutShortcut) 449 .setPkg(TEST_PACKAGE_A) 450 .build()) 451 .setId(1)); 452 mClock.advanceTime(MIN_LINGER_DURATION); 453 454 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 455 any()); 456 } 457 458 @Test testDoNotUpdateAppWidgetIfNoPackage()459 public void testDoNotUpdateAppWidgetIfNoPackage() throws Exception { 460 int[] widgetIdsArray = {}; 461 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 462 463 StatusBarNotification sbnWithoutPackageName = new SbnBuilder() 464 .setNotification(createMessagingStyleNotification( 465 SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ false)) 466 .build(); 467 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 468 .setSbn(sbnWithoutPackageName) 469 .setId(1)); 470 mClock.advanceTime(MIN_LINGER_DURATION); 471 472 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 473 any()); 474 } 475 476 @Test testDoNotUpdateAppWidgetIfNonConversationChannelModified()477 public void testDoNotUpdateAppWidgetIfNonConversationChannelModified() throws Exception { 478 int[] widgetIdsArray = {1}; 479 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 480 481 NotificationChannel channel = 482 new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT); 483 484 mNoMan.issueChannelModification(TEST_PACKAGE_A, 485 UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH); 486 mClock.advanceTime(MIN_LINGER_DURATION); 487 488 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 489 any()); 490 } 491 492 @Test testUpdateAppWidgetIfConversationChannelModified()493 public void testUpdateAppWidgetIfConversationChannelModified() throws Exception { 494 int[] widgetIdsArray = {1}; 495 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 496 497 when(mUserManager.isUserUnlocked(any())).thenReturn(true); 498 499 NotificationChannel channel = 500 new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT); 501 channel.setConversationId(TEST_PARENT_CHANNEL_ID, TEST_CONVERSATION_ID); 502 503 mNoMan.issueChannelModification(TEST_PACKAGE_A, 504 UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH); 505 mClock.advanceTime(MIN_LINGER_DURATION); 506 507 verify(mAppWidgetManager, times(1)).updateAppWidget(anyInt(), any()); 508 } 509 510 @Test testOnNotificationChannelModified_userLocked()511 public void testOnNotificationChannelModified_userLocked() { 512 int[] widgetIdsArray = {1}; 513 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 514 515 when(mUserManager.isUserUnlocked(any())).thenReturn(false); 516 517 NotificationChannel channel = 518 new NotificationChannel(TEST_CHANNEL_ID, TEST_CHANNEL_NAME, IMPORTANCE_DEFAULT); 519 channel.setConversationId(TEST_PARENT_CHANNEL_ID, TEST_CONVERSATION_ID); 520 521 mNoMan.issueChannelModification(TEST_PACKAGE_A, 522 UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH); 523 mClock.advanceTime(MIN_LINGER_DURATION); 524 525 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), any()); 526 } 527 528 @Test testDoNotUpdateNotificationPostedIfDifferentShortcutId()529 public void testDoNotUpdateNotificationPostedIfDifferentShortcutId() throws Exception { 530 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 531 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 532 533 StatusBarNotification sbn = createNotification( 534 OTHER_SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false); 535 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 536 .setSbn(sbn) 537 .setId(1)); 538 mClock.advanceTime(MIN_LINGER_DURATION); 539 540 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 541 any()); 542 } 543 544 @Test testDoNotUpdateNotificationPostedIfDifferentPackageName()545 public void testDoNotUpdateNotificationPostedIfDifferentPackageName() throws Exception { 546 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 547 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 548 549 StatusBarNotification sbnWithDifferentPackageName = new SbnBuilder() 550 .setNotification(createMessagingStyleNotification( 551 SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ false)) 552 .setPkg(TEST_PACKAGE_B) 553 .build(); 554 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 555 .setSbn(sbnWithDifferentPackageName) 556 .setId(1)); 557 mClock.advanceTime(MIN_LINGER_DURATION); 558 559 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 560 any()); 561 } 562 563 @Test testDoNotUpdateNotificationRemovedIfDifferentShortcutId()564 public void testDoNotUpdateNotificationRemovedIfDifferentShortcutId() throws Exception { 565 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 566 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 567 568 StatusBarNotification sbn = createNotification( 569 OTHER_SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false); 570 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 571 .setSbn(sbn) 572 .setId(1)); 573 mClock.advanceTime(4); 574 NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0); 575 mClock.advanceTime(MIN_LINGER_DURATION); 576 577 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 578 any()); 579 } 580 581 @Test testDoNotUpdateNotificationRemovedIfDifferentPackageName()582 public void testDoNotUpdateNotificationRemovedIfDifferentPackageName() throws Exception { 583 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 584 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 585 586 StatusBarNotification sbnWithDifferentPackageName = new SbnBuilder() 587 .setNotification(createMessagingStyleNotification( 588 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false)) 589 .setPkg(TEST_PACKAGE_B) 590 .build(); 591 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 592 .setSbn(sbnWithDifferentPackageName) 593 .setId(1)); 594 mClock.advanceTime(4); 595 NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0); 596 mClock.advanceTime(MIN_LINGER_DURATION); 597 598 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 599 any()); 600 } 601 602 @Test testDoNotUpdateStatusPostedIfDifferentShortcutId()603 public void testDoNotUpdateStatusPostedIfDifferentShortcutId() throws Exception { 604 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 605 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 606 607 ConversationStatus status1 = new ConversationStatus.Builder(OTHER_SHORTCUT_ID, 608 ACTIVITY_GAME).setDescription("Playing a game!").build(); 609 ConversationStatus status2 = new ConversationStatus.Builder(OTHER_SHORTCUT_ID, 610 ACTIVITY_BIRTHDAY).build(); 611 ConversationChannel conversationChannel = getConversationWithShortcutId( 612 new PeopleTileKey(OTHER_SHORTCUT_ID, 0, TEST_PACKAGE_A), 613 Arrays.asList(status1, status2)); 614 mManager.updateWidgetsWithConversationChanged(conversationChannel); 615 mClock.advanceTime(MIN_LINGER_DURATION); 616 617 verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), 618 any()); 619 } 620 621 @Test testUpdateStatusPostedIfExistingTile()622 public void testUpdateStatusPostedIfExistingTile() throws Exception { 623 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 624 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 625 626 ConversationStatus status = new ConversationStatus.Builder(SHORTCUT_ID, 627 ACTIVITY_GAME).setDescription("Playing a game!").build(); 628 ConversationChannel conversationChannel = getConversationWithShortcutId( 629 new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A), 630 Arrays.asList(status)); 631 mManager.updateWidgetsWithConversationChanged(conversationChannel); 632 mClock.advanceTime(MIN_LINGER_DURATION); 633 634 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 635 assertThat(tile.getStatuses()).containsExactly(status); 636 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 637 any()); 638 } 639 640 @Test testUpdateStatusPostedOnTwoExistingTiles()641 public void testUpdateStatusPostedOnTwoExistingTiles() throws Exception { 642 addSecondWidgetForPersonTile(); 643 644 ConversationStatus status = new ConversationStatus.Builder(SHORTCUT_ID, 645 ACTIVITY_ANNIVERSARY).build(); 646 ConversationChannel conversationChannel = getConversationWithShortcutId( 647 new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A), Arrays.asList(status)); 648 mManager.updateWidgetsWithConversationChanged(conversationChannel); 649 mClock.advanceTime(MIN_LINGER_DURATION); 650 651 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 652 any()); 653 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(SECOND_WIDGET_ID_WITH_SHORTCUT), 654 any()); 655 } 656 657 @Test testUpdateNotificationPostedIfExistingTile()658 public void testUpdateNotificationPostedIfExistingTile() throws Exception { 659 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 660 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 661 NotificationEntryBuilder builder = new NotificationEntryBuilder() 662 .setSbn(createNotification( 663 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false)) 664 .setShortcutInfo(mShortcutInfo) 665 .setId(1); 666 NotificationEntry entry = builder.build(); 667 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 668 669 NotifEvent notif1 = mNoMan.postNotif(builder); 670 mClock.advanceTime(MIN_LINGER_DURATION); 671 672 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 673 assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 674 assertThat(tile.getLastInteractionTimestamp()).isEqualTo(SBN_POST_TIME); 675 assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1); 676 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 677 any()); 678 } 679 680 @Test testUpdateNotificationPostedOnTwoExistingTiles()681 public void testUpdateNotificationPostedOnTwoExistingTiles() throws Exception { 682 addSecondWidgetForPersonTile(); 683 684 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 685 .setSbn(createNotification( 686 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false)) 687 .setId(1)); 688 mClock.advanceTime(MIN_LINGER_DURATION); 689 690 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 691 any()); 692 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(SECOND_WIDGET_ID_WITH_SHORTCUT), 693 any()); 694 } 695 696 @Test testUpdateNotificationOnExistingTileAfterRemovingTileForSamePerson()697 public void testUpdateNotificationOnExistingTileAfterRemovingTileForSamePerson() 698 throws Exception { 699 addSecondWidgetForPersonTile(); 700 701 PeopleSpaceUtils.removeSharedPreferencesStorageForTile( 702 mContext, KEY, SECOND_WIDGET_ID_WITH_SHORTCUT, EMPTY_STRING); 703 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 704 .setSbn(createNotification( 705 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false)) 706 .setId(1)); 707 mClock.advanceTime(MIN_LINGER_DURATION); 708 709 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 710 any()); 711 verify(mAppWidgetManager, never()).updateAppWidget(eq(SECOND_WIDGET_ID_WITH_SHORTCUT), 712 any()); 713 } 714 715 @Test testUpdateMissedCallNotificationWithoutContentPostedIfExistingTile()716 public void testUpdateMissedCallNotificationWithoutContentPostedIfExistingTile() 717 throws Exception { 718 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 719 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 720 NotificationEntryBuilder builder = new NotificationEntryBuilder() 721 .setSbn(createNotification( 722 SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ true)) 723 .setShortcutInfo(mShortcutInfo) 724 .setId(1); 725 NotificationEntry entry = builder.build(); 726 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 727 728 NotifEvent notif1 = mNoMan.postNotif(builder); 729 mClock.advanceTime(MIN_LINGER_DURATION); 730 731 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 732 assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 733 assertThat(tile.getNotificationContent()) 734 .isEqualTo(mContext.getString(R.string.missed_call)); 735 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 736 any()); 737 } 738 739 @Test testUpdateMissedCallNotificationWithContentPostedIfExistingTile()740 public void testUpdateMissedCallNotificationWithContentPostedIfExistingTile() 741 throws Exception { 742 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 743 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 744 NotificationEntryBuilder builder = new NotificationEntryBuilder() 745 .setSbn(createNotification( 746 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) 747 .setShortcutInfo(mShortcutInfo) 748 .setId(1); 749 NotificationEntry entry = builder.build(); 750 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 751 752 NotifEvent notif1 = mNoMan.postNotif(builder); 753 mClock.advanceTime(MIN_LINGER_DURATION); 754 755 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 756 assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 757 assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1); 758 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 759 any()); 760 } 761 762 @Test testUpdateMissedCallNotificationWithContentPostedIfMatchingUriTile()763 public void testUpdateMissedCallNotificationWithContentPostedIfMatchingUriTile() 764 throws Exception { 765 int[] widgetIdsArray = 766 {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; 767 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 768 NotificationEntryBuilder builder = new NotificationEntryBuilder() 769 .setSbn(createNotification( 770 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) 771 .setShortcutInfo(mShortcutInfo) 772 .setId(1); 773 NotificationEntry entry = builder.build(); 774 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 775 776 NotifEvent notif1 = mNoMan.postNotif(builder); 777 mClock.advanceTime(MIN_LINGER_DURATION); 778 779 PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 780 assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 781 assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( 782 NOTIFICATION_CONTENT_1); 783 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 784 any()); 785 PeopleSpaceTile tileWithSameUri = mManager.mTiles.get(WIDGET_ID_WITH_SAME_URI); 786 assertThat(tileWithSameUri.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 787 assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1); 788 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), 789 any()); 790 } 791 792 @Test testRemoveMissedCallNotificationWithContentPostedIfMatchingUriTile()793 public void testRemoveMissedCallNotificationWithContentPostedIfMatchingUriTile() 794 throws Exception { 795 int[] widgetIdsArray = 796 {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; 797 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 798 NotificationEntryBuilder builder = new NotificationEntryBuilder() 799 .setSbn(createNotification( 800 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) 801 .setShortcutInfo(mShortcutInfo) 802 .setId(1); 803 804 NotificationEntry entry = builder.build(); 805 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 806 807 NotifEvent notif1 = mNoMan.postNotif(builder); 808 mClock.advanceTime(MIN_LINGER_DURATION); 809 810 when(mNotifCollection.getAllNotifs()).thenReturn(List.of()); 811 NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn.cloneLight(), 0); 812 mClock.advanceTime(MIN_LINGER_DURATION); 813 814 PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 815 assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(null); 816 assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo(null); 817 verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 818 any()); 819 PeopleSpaceTile tileWithSameUri = mManager.mTiles.get(WIDGET_ID_WITH_SAME_URI); 820 assertThat(tileWithSameUri.getNotificationKey()).isEqualTo(null); 821 assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(null); 822 verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), 823 any()); 824 } 825 826 @Test testUpdateMissedCallNotificationWithContentPostedIfMatchingUriTileFromSender()827 public void testUpdateMissedCallNotificationWithContentPostedIfMatchingUriTileFromSender() 828 throws Exception { 829 int[] widgetIdsArray = 830 {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; 831 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 832 Notification notificationWithPersonOnlyInSender = 833 createMessagingStyleNotificationWithoutExtras( 834 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ 835 true).build(); 836 StatusBarNotification sbn = new SbnBuilder() 837 .setNotification(notificationWithPersonOnlyInSender) 838 .setPkg(TEST_PACKAGE_A) 839 .setUid(0) 840 .setUser(new UserHandle(0)) 841 .build(); 842 NotificationEntryBuilder builder = new NotificationEntryBuilder() 843 .setRank(1) 844 .setShortcutInfo(mShortcutInfo) 845 .setSbn(sbn) 846 .setId(1); 847 NotificationEntry entry = builder.build(); 848 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 849 850 NotifEvent notif1 = mNoMan.postNotif(builder); 851 mClock.advanceTime(MIN_LINGER_DURATION); 852 853 PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 854 assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 855 assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( 856 NOTIFICATION_CONTENT_1); 857 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 858 any()); 859 PeopleSpaceTile tileWithSameUri = mManager.mTiles.get(WIDGET_ID_WITH_SAME_URI); 860 assertThat(tileWithSameUri.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 861 assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1); 862 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), 863 any()); 864 } 865 866 @Test testDoNotUpdateMissedCallNotificationWithContentPostedIfNoPersonsAttached()867 public void testDoNotUpdateMissedCallNotificationWithContentPostedIfNoPersonsAttached() 868 throws Exception { 869 int[] widgetIdsArray = 870 {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; 871 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 872 // Notification posted without any Person attached. 873 Notification notificationWithoutPersonObject = 874 createMessagingStyleNotificationWithoutExtras( 875 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ 876 true).setStyle(new Notification.MessagingStyle("sender") 877 .addMessage( 878 new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT_1, 10, 879 "sender")) 880 ).build(); 881 StatusBarNotification sbn = new SbnBuilder() 882 .setNotification(notificationWithoutPersonObject) 883 .setPkg(TEST_PACKAGE_A) 884 .setUid(0) 885 .setUser(new UserHandle(0)) 886 .build(); 887 NotificationEntryBuilder builder = new NotificationEntryBuilder() 888 .setSbn(sbn) 889 .setShortcutInfo(mShortcutInfo) 890 .setId(1); 891 NotificationEntry entry = builder.build(); 892 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 893 894 NotifEvent notif1 = mNoMan.postNotif(builder); 895 896 mClock.advanceTime(MIN_LINGER_DURATION); 897 898 PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 899 assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 900 assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( 901 NOTIFICATION_CONTENT_1); 902 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 903 any()); 904 // Do not update since notification doesn't include a Person reference. 905 verify(mAppWidgetManager, times(0)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), 906 any()); 907 } 908 909 @Test testDoNotUpdateMissedCallNotificationWithContentPostedIfNotMatchingUriTile()910 public void testDoNotUpdateMissedCallNotificationWithContentPostedIfNotMatchingUriTile() 911 throws Exception { 912 clearStorage(); 913 addTileForWidget(PERSON_TILE, WIDGET_ID_WITH_SHORTCUT); 914 addTileForWidget(PERSON_TILE_WITH_SAME_URI.toBuilder().setContactUri( 915 Uri.parse("different_uri")).build(), WIDGET_ID_WITH_DIFFERENT_URI); 916 int[] widgetIdsArray = 917 {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_DIFFERENT_URI}; 918 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 919 NotificationEntryBuilder builder = new NotificationEntryBuilder() 920 .setSbn(createNotification( 921 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) 922 .setShortcutInfo(mShortcutInfo) 923 .setId(1); 924 NotificationEntry entry = builder.build(); 925 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 926 927 NotifEvent notif1 = mNoMan.postNotif(builder); 928 mClock.advanceTime(MIN_LINGER_DURATION); 929 930 PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 931 assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 932 assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( 933 NOTIFICATION_CONTENT_1); 934 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 935 any()); 936 // Do not update since missing permission to read contacts. 937 verify(mAppWidgetManager, times(0)).updateAppWidget(eq(WIDGET_ID_WITH_DIFFERENT_URI), 938 any()); 939 } 940 941 @Test testDoNotUpdateMissedCallIfMatchingUriTileMissingReadContactsPermission()942 public void testDoNotUpdateMissedCallIfMatchingUriTileMissingReadContactsPermission() 943 throws Exception { 944 when(mPackageManager.checkPermission(any(), 945 eq(PERSON_TILE_WITH_SAME_URI.getPackageName()))).thenReturn( 946 PERMISSION_HARD_DENIED); 947 int[] widgetIdsArray = 948 {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; 949 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 950 NotificationEntryBuilder builder = new NotificationEntryBuilder() 951 .setSbn(createNotification( 952 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) 953 .setShortcutInfo(mShortcutInfo) 954 .setId(1); 955 NotificationEntry entry = builder.build(); 956 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(entry)); 957 958 NotifEvent notif1 = mNoMan.postNotif(builder); 959 mClock.advanceTime(MIN_LINGER_DURATION); 960 961 PeopleSpaceTile tileWithMissedCallOrigin = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 962 assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); 963 assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( 964 NOTIFICATION_CONTENT_1); 965 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 966 any()); 967 // Do not update since missing permission to read contacts. 968 PeopleSpaceTile tileNoNotification = mManager.mTiles.get(WIDGET_ID_WITH_SAME_URI); 969 assertThat(tileNoNotification.getNotificationKey()).isNull(); 970 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), 971 any()); 972 } 973 974 @Test testUpdateNotificationRemovedIfExistingTile()975 public void testUpdateNotificationRemovedIfExistingTile() throws Exception { 976 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; 977 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 978 979 StatusBarNotification sbn = createNotification( 980 SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false); 981 NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() 982 .setSbn(sbn) 983 .setId(1)); 984 mClock.advanceTime(MIN_LINGER_DURATION); 985 long timestampBeforeNotificationClear = System.currentTimeMillis(); 986 NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0); 987 mClock.advanceTime(MIN_LINGER_DURATION); 988 989 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 990 assertThat(tile.getNotificationKey()).isEqualTo(null); 991 assertThat(tile.getLastInteractionTimestamp()).isLessThan( 992 timestampBeforeNotificationClear); 993 assertThat(tile.getNotificationContent()).isEqualTo(null); 994 assertThat(tile.getNotificationDataUri()).isEqualTo(null); 995 verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 996 any()); 997 } 998 999 @Test testAddThenReconfigureWidgetsUpdatesStorageCacheAndListeners()1000 public void testAddThenReconfigureWidgetsUpdatesStorageCacheAndListeners() 1001 throws Exception { 1002 clearStorage(); 1003 mManager.addNewWidget(WIDGET_ID_WITH_SHORTCUT, new PeopleTileKey(PERSON_TILE)); 1004 // Check storage. 1005 SharedPreferences widgetSp = mContext.getSharedPreferences( 1006 String.valueOf(WIDGET_ID_WITH_SHORTCUT), 1007 Context.MODE_PRIVATE); 1008 assertThat(widgetSp.getString(PACKAGE_NAME, null)).isEqualTo(TEST_PACKAGE_A); 1009 assertThat(widgetSp.getString(PeopleSpaceUtils.SHORTCUT_ID, null)).isEqualTo( 1010 PERSON_TILE.getId()); 1011 assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(0); 1012 // Check listener and caching. 1013 verify(mPeopleManager).registerConversationListener(eq(TEST_PACKAGE_A), anyInt(), 1014 eq(SHORTCUT_ID), any(), 1015 any()); 1016 verify(mLauncherApps, times(1)).cacheShortcuts( 1017 eq(TEST_PACKAGE_A), 1018 eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)), 1019 eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); 1020 1021 // Reconfigure WIDGET_ID_WITH_SHORTCUT from PERSON_TILE to PERSON_TILE_WITH_SAME_URI 1022 mManager.addNewWidget( 1023 WIDGET_ID_WITH_SHORTCUT, new PeopleTileKey(PERSON_TILE_WITH_SAME_URI)); 1024 1025 // Check listener is removed and shortcut is uncached. 1026 verify(mPeopleManager).unregisterConversationListener(any()); 1027 verify(mLauncherApps).uncacheShortcuts(eq(TEST_PACKAGE_A), 1028 eq(Arrays.asList(PERSON_TILE.getId())), eq(UserHandle.of(0)), 1029 eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); 1030 // Check reconfigured storage from TEST_PACKAGE_A to B and SHORTCUT_ID to OTHER_SHORTCUT_ID. 1031 assertThat(widgetSp.getString(PACKAGE_NAME, null)).isEqualTo(TEST_PACKAGE_B); 1032 assertThat(widgetSp.getString(PeopleSpaceUtils.SHORTCUT_ID, null)).isEqualTo( 1033 OTHER_SHORTCUT_ID); 1034 assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(0); 1035 // Check listener & caching are reconfigured to TEST_PACKAGE_B and OTHER_SHORTCUT_ID. 1036 verify(mPeopleManager, times(1)).registerConversationListener(eq(TEST_PACKAGE_B), anyInt(), 1037 eq(OTHER_SHORTCUT_ID), any(), 1038 any()); 1039 verify(mLauncherApps, times(1)).cacheShortcuts( 1040 eq(TEST_PACKAGE_B), 1041 eq(Arrays.asList(OTHER_SHORTCUT_ID)), eq(UserHandle.of(0)), 1042 eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); 1043 } 1044 1045 @Test testDeleteAllWidgetsForConversationsUncachesShortcutAndRemovesListeners()1046 public void testDeleteAllWidgetsForConversationsUncachesShortcutAndRemovesListeners() 1047 throws Exception { 1048 addSecondWidgetForPersonTile(); 1049 mManager.updateWidgets(new int[]{WIDGET_ID_WITH_SHORTCUT, SECOND_WIDGET_ID_WITH_SHORTCUT}); 1050 1051 // Delete only one widget for the conversation in background. 1052 mManager.deleteWidgets(new int[]{WIDGET_ID_WITH_SHORTCUT}); 1053 mClock.advanceTime(MIN_LINGER_DURATION); 1054 1055 // Check deleted storage. 1056 SharedPreferences widgetSp = mContext.getSharedPreferences( 1057 String.valueOf(WIDGET_ID_WITH_SHORTCUT), 1058 Context.MODE_PRIVATE); 1059 assertThat(widgetSp.getString(PACKAGE_NAME, null)).isNull(); 1060 assertThat(widgetSp.getString(SHORTCUT_ID, null)).isNull(); 1061 assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID); 1062 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); 1063 assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())).containsExactly( 1064 String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT)); 1065 // Check listener & shortcut caching remain for other widget. 1066 verify(mPeopleManager, never()).unregisterConversationListener(any()); 1067 verify(mLauncherApps, never()).uncacheShortcuts(eq(TEST_PACKAGE_A), 1068 eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)), 1069 eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); 1070 1071 // Delete all widgets for the conversation in background. 1072 mManager.deleteWidgets(new int[]{SECOND_WIDGET_ID_WITH_SHORTCUT}); 1073 mClock.advanceTime(MIN_LINGER_DURATION); 1074 1075 // Check deleted storage. 1076 SharedPreferences secondWidgetSp = mContext.getSharedPreferences( 1077 String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT), 1078 Context.MODE_PRIVATE); 1079 assertThat(secondWidgetSp.getString(PACKAGE_NAME, null)).isNull(); 1080 assertThat(secondWidgetSp.getString(SHORTCUT_ID, null)).isNull(); 1081 assertThat(secondWidgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID); 1082 assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())).isEmpty(); 1083 // Check listener is removed and shortcut is uncached. 1084 verify(mPeopleManager, times(1)).unregisterConversationListener(any()); 1085 verify(mLauncherApps, times(1)).uncacheShortcuts(eq(TEST_PACKAGE_A), 1086 eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)), 1087 eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); 1088 } 1089 1090 @Test testUpdateWidgetsWithEmptyOptionsAddsPeopleTileToOptions()1091 public void testUpdateWidgetsWithEmptyOptionsAddsPeopleTileToOptions() throws Exception { 1092 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; 1093 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 1094 when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT))) 1095 .thenReturn(new Bundle()); 1096 1097 mManager.updateWidgets(widgetIdsArray); 1098 mClock.advanceTime(MIN_LINGER_DURATION); 1099 1100 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 1101 any()); 1102 } 1103 1104 @Test testOnAppWidgetOptionsChangedNoWidgetAdded()1105 public void testOnAppWidgetOptionsChangedNoWidgetAdded() { 1106 Bundle newOptions = new Bundle(); 1107 mManager.onAppWidgetOptionsChanged(SECOND_WIDGET_ID_WITH_SHORTCUT, newOptions); 1108 1109 // Check that options is not modified 1110 verify(mAppWidgetManager, never()).updateAppWidgetOptions( 1111 eq(SECOND_WIDGET_ID_WITH_SHORTCUT), any()); 1112 // Check listener is not added and shortcut is not cached. 1113 verify(mPeopleManager, never()).registerConversationListener(any(), anyInt(), any(), any(), 1114 any()); 1115 verify(mLauncherApps, never()).cacheShortcuts(any(), any(), any(), anyInt()); 1116 // Check no added storage. 1117 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); 1118 assertThat(sp.getStringSet(KEY.toString(), new HashSet<>())) 1119 .doesNotContain(SECOND_WIDGET_ID_WITH_SHORTCUT); 1120 SharedPreferences widgetSp = mContext.getSharedPreferences( 1121 String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT), 1122 Context.MODE_PRIVATE); 1123 assertThat(widgetSp.getString(PACKAGE_NAME, EMPTY_STRING)).isEqualTo(EMPTY_STRING); 1124 assertThat(widgetSp.getString(SHORTCUT_ID, EMPTY_STRING)).isEqualTo(EMPTY_STRING); 1125 assertThat(widgetSp.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID); 1126 1127 } 1128 1129 @Test testOnAppWidgetOptionsChangedWidgetAdded()1130 public void testOnAppWidgetOptionsChangedWidgetAdded() { 1131 Bundle newOptions = new Bundle(); 1132 newOptions.putString(PeopleSpaceUtils.SHORTCUT_ID, SHORTCUT_ID); 1133 newOptions.putInt(USER_ID, 0); 1134 newOptions.putString(PACKAGE_NAME, TEST_PACKAGE_A); 1135 when(mAppWidgetManager.getAppWidgetOptions(eq(SECOND_WIDGET_ID_WITH_SHORTCUT))) 1136 .thenReturn(newOptions); 1137 1138 mManager.onAppWidgetOptionsChanged(SECOND_WIDGET_ID_WITH_SHORTCUT, newOptions); 1139 1140 verify(mAppWidgetManager, times(1)).updateAppWidgetOptions( 1141 eq(SECOND_WIDGET_ID_WITH_SHORTCUT), mBundleArgumentCaptor.capture()); 1142 Bundle first = mBundleArgumentCaptor.getValue(); 1143 assertThat(first.getString(PeopleSpaceUtils.SHORTCUT_ID, EMPTY_STRING)) 1144 .isEqualTo(EMPTY_STRING); 1145 assertThat(first.getInt(USER_ID, INVALID_USER_ID)).isEqualTo(INVALID_USER_ID); 1146 assertThat(first.getString(PACKAGE_NAME, EMPTY_STRING)).isEqualTo(EMPTY_STRING); 1147 verify(mLauncherApps, times(1)).cacheShortcuts(eq(TEST_PACKAGE_A), 1148 eq(Arrays.asList(SHORTCUT_ID)), eq(UserHandle.of(0)), 1149 eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); 1150 } 1151 1152 @Test testGetPeopleTileFromPersistentStorageExistingConversation()1153 public void testGetPeopleTileFromPersistentStorageExistingConversation() 1154 throws Exception { 1155 ConversationChannel channel = getConversationWithShortcutId( 1156 new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A)); 1157 when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(channel); 1158 PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); 1159 PeopleSpaceTile tile = mManager 1160 .getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT, true); 1161 assertThat(tile.getId()).isEqualTo(key.getShortcutId()); 1162 } 1163 1164 @Test testGetPeopleTileFromPersistentStorageNoConversation()1165 public void testGetPeopleTileFromPersistentStorageNoConversation() throws Exception { 1166 when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null); 1167 PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); 1168 PeopleSpaceTile tile = mManager 1169 .getTileFromPersistentStorage(key, WIDGET_ID_WITH_SHORTCUT, false); 1170 assertThat(tile).isNull(); 1171 } 1172 1173 @Test testRequestPinAppWidgetExistingConversation()1174 public void testRequestPinAppWidgetExistingConversation() throws Exception { 1175 ConversationChannel channel = getConversationWithShortcutId( 1176 new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A)); 1177 when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)) 1178 .thenReturn(channel); 1179 when(mAppWidgetManager.requestPinAppWidget(any(), any(), any())).thenReturn(true); 1180 1181 ShortcutInfo info = new ShortcutInfo.Builder(mMockContext, SHORTCUT_ID).build(); 1182 boolean valid = mManager.requestPinAppWidget(info, new Bundle()); 1183 1184 assertThat(valid).isTrue(); 1185 verify(mAppWidgetManager, times(1)).requestPinAppWidget( 1186 any(), any(), any()); 1187 } 1188 1189 @Test testRequestPinAppWidgetNoConversation()1190 public void testRequestPinAppWidgetNoConversation() throws Exception { 1191 when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null); 1192 1193 ShortcutInfo info = new ShortcutInfo.Builder(mMockContext, SHORTCUT_ID).build(); 1194 boolean valid = mManager.requestPinAppWidget(info, new Bundle()); 1195 1196 assertThat(valid).isFalse(); 1197 verify(mAppWidgetManager, never()).requestPinAppWidget(any(), any(), any()); 1198 } 1199 1200 @Test testAugmentTileFromNotifications()1201 public void testAugmentTileFromNotifications() { 1202 clearStorage(); 1203 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); 1204 assertThat(sp.getString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), null)).isEqualTo(null); 1205 PeopleSpaceTile tile = 1206 new PeopleSpaceTile 1207 .Builder(SHORTCUT_ID, "userName", ICON, new Intent()) 1208 .setPackageName(TEST_PACKAGE_A) 1209 .setUserHandle(new UserHandle(0)) 1210 .build(); 1211 1212 PeopleTileKey key = new PeopleTileKey(tile); 1213 PeopleSpaceTile actual = mManager.augmentTileFromNotifications(tile, key, EMPTY_STRING, 1214 Map.of(new PeopleTileKey(mNotificationEntry), 1215 new HashSet<>(Collections.singleton(mNotificationEntry))), 1216 Optional.of(WIDGET_ID_WITH_SHORTCUT)); 1217 1218 assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_CONTENT_1); 1219 assertThat(sp.getString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), null)).isEqualTo( 1220 URI.toString()); 1221 } 1222 1223 @Test testAugmentTileFromNotificationsDifferentShortcutId()1224 public void testAugmentTileFromNotificationsDifferentShortcutId() { 1225 PeopleSpaceTile tile = 1226 new PeopleSpaceTile 1227 .Builder(OTHER_SHORTCUT_ID, "userName", ICON, new Intent()) 1228 .setPackageName(TEST_PACKAGE_A) 1229 .setUserHandle(new UserHandle(0)) 1230 .build(); 1231 PeopleTileKey key = new PeopleTileKey(tile); 1232 PeopleSpaceTile actual = mManager 1233 .augmentTileFromNotifications(tile, key, EMPTY_STRING, 1234 Map.of(new PeopleTileKey(mNotificationEntry), 1235 new HashSet<>(Collections.singleton(mNotificationEntry))), 1236 Optional.empty()); 1237 1238 assertThat(actual.getNotificationContent()).isEqualTo(null); 1239 } 1240 1241 @Test testAugmentTileFromNotificationEntryManager()1242 public void testAugmentTileFromNotificationEntryManager() { 1243 PeopleSpaceTile tile = 1244 new PeopleSpaceTile 1245 .Builder(SHORTCUT_ID, "userName", ICON, new Intent()) 1246 .setPackageName(TEST_PACKAGE_A) 1247 .setUserHandle(new UserHandle(0)) 1248 .build(); 1249 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(mNotificationEntry)); 1250 1251 PeopleSpaceTile actual = 1252 mManager.augmentTileFromNotificationEntryManager(tile, 1253 Optional.of(WIDGET_ID_WITH_SHORTCUT)); 1254 1255 assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_CONTENT_1); 1256 1257 verify(mNotifCollection, times(1)).getAllNotifs(); 1258 } 1259 1260 @Test testAugmentTileFromNotificationEntryManager_notificationHidden()1261 public void testAugmentTileFromNotificationEntryManager_notificationHidden() { 1262 when(mBubbles.isBubbleNotificationSuppressedFromShade(any(), any())).thenReturn(true); 1263 PeopleSpaceTile tile = 1264 new PeopleSpaceTile 1265 .Builder(SHORTCUT_ID, "userName", ICON, new Intent()) 1266 .setPackageName(TEST_PACKAGE_A) 1267 .setUserHandle(new UserHandle(0)) 1268 .build(); 1269 when(mNotifCollection.getAllNotifs()).thenReturn(List.of(mNotificationEntry)); 1270 1271 PeopleSpaceTile actual = 1272 mManager.augmentTileFromNotificationEntryManager(tile, 1273 Optional.of(WIDGET_ID_WITH_SHORTCUT)); 1274 1275 assertThat(TextUtils.isEmpty(actual.getNotificationContent())).isTrue(); 1276 1277 verify(mNotifCollection, times(1)).getAllNotifs(); 1278 } 1279 1280 @Test testUpdateWidgetsFromBroadcastInBackgroundBootCompleteWithPackageUninstalled()1281 public void testUpdateWidgetsFromBroadcastInBackgroundBootCompleteWithPackageUninstalled() 1282 throws Exception { 1283 when(mPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenThrow( 1284 PackageManager.NameNotFoundException.class); 1285 1286 // We should remove widgets if the package is uninstalled at next reboot if we missed the 1287 // package removed broadcast. 1288 mManager.updateWidgetsFromBroadcastInBackground(ACTION_BOOT_COMPLETED); 1289 1290 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1291 assertThat(tile).isNull(); 1292 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 1293 any()); 1294 } 1295 1296 @Test testUpdateWidgetsFromBroadcastInBackgroundPackageRemovedWithPackageUninstalled()1297 public void testUpdateWidgetsFromBroadcastInBackgroundPackageRemovedWithPackageUninstalled() 1298 throws Exception { 1299 when(mPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenThrow( 1300 PackageManager.NameNotFoundException.class); 1301 1302 mManager.updateWidgetsFromBroadcastInBackground(ACTION_PACKAGE_REMOVED); 1303 1304 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1305 assertThat(tile).isNull(); 1306 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 1307 any()); 1308 } 1309 1310 @Test testUpdateWidgetsFromBroadcastInBackground()1311 public void testUpdateWidgetsFromBroadcastInBackground() { 1312 mManager.updateWidgetsFromBroadcastInBackground(ACTION_BOOT_COMPLETED); 1313 1314 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1315 assertThat(tile.isPackageSuspended()).isFalse(); 1316 assertThat(tile.isUserQuieted()).isFalse(); 1317 assertThat(tile.canBypassDnd()).isFalse(); 1318 assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS); 1319 verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), 1320 any()); 1321 } 1322 1323 @Test testUpdateWidgetsFromBroadcastInBackgroundWithUserQuieted()1324 public void testUpdateWidgetsFromBroadcastInBackgroundWithUserQuieted() { 1325 when(mUserManager.isQuietModeEnabled(any())).thenReturn(true); 1326 1327 mManager.updateWidgetsFromBroadcastInBackground(ACTION_BOOT_COMPLETED); 1328 1329 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1330 assertThat(tile.isPackageSuspended()).isFalse(); 1331 assertThat(tile.isUserQuieted()).isTrue(); 1332 assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS); 1333 } 1334 1335 @Test testUpdateWidgetsFromBroadcastInBackgroundWithPackageSuspended()1336 public void testUpdateWidgetsFromBroadcastInBackgroundWithPackageSuspended() throws Exception { 1337 when(mPackageManager.isPackageSuspended(any())).thenReturn(true); 1338 1339 mManager.updateWidgetsFromBroadcastInBackground(ACTION_PACKAGES_SUSPENDED); 1340 1341 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1342 assertThat(tile.isPackageSuspended()).isTrue(); 1343 assertThat(tile.isUserQuieted()).isFalse(); 1344 assertThat(tile.getNotificationPolicyState()).isEqualTo(SHOW_CONVERSATIONS); 1345 } 1346 1347 @Test testUpdateWidgetsFromBroadcastInBackgroundNotInDnd()1348 public void testUpdateWidgetsFromBroadcastInBackgroundNotInDnd() { 1349 int expected = 0; 1350 mManager.updateWidgetsFromBroadcastInBackground(NotificationManager 1351 .ACTION_INTERRUPTION_FILTER_CHANGED); 1352 1353 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1354 assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS); 1355 } 1356 1357 @Test testUpdateWidgetsFromBroadcastInBackgroundAllConversations()1358 public void testUpdateWidgetsFromBroadcastInBackgroundAllConversations() { 1359 int expected = 0; 1360 when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( 1361 INTERRUPTION_FILTER_PRIORITY); 1362 when(mNotificationPolicy.allowConversations()).thenReturn(true); 1363 setFinalField("priorityConversationSenders", CONVERSATION_SENDERS_ANYONE); 1364 1365 mManager.updateWidgetsFromBroadcastInBackground(NotificationManager 1366 .ACTION_INTERRUPTION_FILTER_CHANGED); 1367 1368 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1369 assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS); 1370 } 1371 1372 @Test testUpdateWidgetsFromBroadcastInBackgroundAllowOnlyImportantConversations()1373 public void testUpdateWidgetsFromBroadcastInBackgroundAllowOnlyImportantConversations() { 1374 int expected = 0; 1375 // Only allow important conversations. 1376 when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( 1377 INTERRUPTION_FILTER_PRIORITY); 1378 when(mNotificationPolicy.allowConversations()).thenReturn(true); 1379 setFinalField("priorityConversationSenders", CONVERSATION_SENDERS_IMPORTANT); 1380 1381 mManager.updateWidgetsFromBroadcastInBackground(NotificationManager 1382 .ACTION_INTERRUPTION_FILTER_CHANGED); 1383 1384 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1385 assertThat(tile.getNotificationPolicyState()).isEqualTo( 1386 expected | SHOW_IMPORTANT_CONVERSATIONS); 1387 } 1388 1389 @Test testUpdateWidgetsFromBroadcastInBackgroundAllowNoConversations()1390 public void testUpdateWidgetsFromBroadcastInBackgroundAllowNoConversations() { 1391 int expected = 0; 1392 when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( 1393 INTERRUPTION_FILTER_PRIORITY); 1394 when(mNotificationPolicy.allowConversations()).thenReturn(false); 1395 1396 mManager.updateWidgetsFromBroadcastInBackground(NotificationManager 1397 .ACTION_INTERRUPTION_FILTER_CHANGED); 1398 1399 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1400 assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | BLOCK_CONVERSATIONS); 1401 } 1402 1403 @Test testUpdateWidgetsFromBroadcastInBackgroundAllowNoConversationsAllowContactMessages()1404 public void testUpdateWidgetsFromBroadcastInBackgroundAllowNoConversationsAllowContactMessages() { 1405 int expected = 0; 1406 when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( 1407 INTERRUPTION_FILTER_PRIORITY); 1408 when(mNotificationPolicy.allowConversations()).thenReturn(false); 1409 when(mNotificationPolicy.allowMessagesFrom()).thenReturn(ZenModeConfig.SOURCE_CONTACT); 1410 when(mNotificationPolicy.allowMessages()).thenReturn(true); 1411 1412 mManager.updateWidgetsFromBroadcastInBackground(ACTION_BOOT_COMPLETED); 1413 1414 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1415 assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONTACTS); 1416 } 1417 1418 @Test testUpdateWidgetsFromBroadcastInBackgroundAllowNoConversationsAllowStarredContactMessages()1419 public void testUpdateWidgetsFromBroadcastInBackgroundAllowNoConversationsAllowStarredContactMessages() { 1420 int expected = 0; 1421 when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( 1422 INTERRUPTION_FILTER_PRIORITY); 1423 when(mNotificationPolicy.allowConversations()).thenReturn(false); 1424 when(mNotificationPolicy.allowMessagesFrom()).thenReturn(ZenModeConfig.SOURCE_STAR); 1425 when(mNotificationPolicy.allowMessages()).thenReturn(true); 1426 1427 mManager.updateWidgetsFromBroadcastInBackground(ACTION_BOOT_COMPLETED); 1428 1429 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1430 assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_STARRED_CONTACTS); 1431 1432 setFinalField("suppressedVisualEffects", SUPPRESSED_EFFECT_FULL_SCREEN_INTENT 1433 | SUPPRESSED_EFFECT_AMBIENT); 1434 mManager.updateWidgetsFromBroadcastInBackground(ACTION_BOOT_COMPLETED); 1435 1436 tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1437 assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS); 1438 } 1439 1440 @Test testUpdateWidgetsFromBroadcastInBackgroundAllowAlarmsOnly()1441 public void testUpdateWidgetsFromBroadcastInBackgroundAllowAlarmsOnly() { 1442 int expected = 0; 1443 when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( 1444 INTERRUPTION_FILTER_ALARMS); 1445 1446 mManager.updateWidgetsFromBroadcastInBackground(NotificationManager 1447 .ACTION_INTERRUPTION_FILTER_CHANGED); 1448 1449 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1450 assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | BLOCK_CONVERSATIONS); 1451 } 1452 1453 @Test testUpdateWidgetsFromBroadcastInBackgroundAllowVisualEffectsAndAllowAlarmsOnly()1454 public void testUpdateWidgetsFromBroadcastInBackgroundAllowVisualEffectsAndAllowAlarmsOnly() { 1455 int expected = 0; 1456 // If we show visuals, but just only make sounds for alarms, still show content in tiles. 1457 when(mNotificationManager.getCurrentInterruptionFilter()).thenReturn( 1458 INTERRUPTION_FILTER_ALARMS); 1459 setFinalField("suppressedVisualEffects", SUPPRESSED_EFFECT_FULL_SCREEN_INTENT 1460 | SUPPRESSED_EFFECT_AMBIENT); 1461 1462 mManager.updateWidgetsFromBroadcastInBackground(ACTION_BOOT_COMPLETED); 1463 1464 PeopleSpaceTile tile = mManager.mTiles.get(WIDGET_ID_WITH_SHORTCUT); 1465 assertThat(tile.getNotificationPolicyState()).isEqualTo(expected | SHOW_CONVERSATIONS); 1466 } 1467 1468 @Test testRemapWidgetFiles()1469 public void testRemapWidgetFiles() { 1470 setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_8, URI); 1471 setStorageForTile(OTHER_SHORTCUT_ID, TEST_PACKAGE_B, WIDGET_ID_11, URI); 1472 1473 mManager.remapWidgetFiles(WIDGETS_MAPPING); 1474 1475 SharedPreferences sp1 = mContext.getSharedPreferences( 1476 String.valueOf(WIDGET_ID_WITH_SHORTCUT), Context.MODE_PRIVATE); 1477 PeopleTileKey key1 = SharedPreferencesHelper.getPeopleTileKey(sp1); 1478 assertThat(key1.getShortcutId()).isEqualTo(SHORTCUT_ID); 1479 assertThat(key1.getPackageName()).isEqualTo(TEST_PACKAGE_A); 1480 1481 SharedPreferences sp4 = mContext.getSharedPreferences( 1482 String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS), Context.MODE_PRIVATE); 1483 PeopleTileKey key4 = SharedPreferencesHelper.getPeopleTileKey(sp4); 1484 assertThat(key4.getShortcutId()).isEqualTo(OTHER_SHORTCUT_ID); 1485 assertThat(key4.getPackageName()).isEqualTo(TEST_PACKAGE_B); 1486 1487 SharedPreferences sp8 = mContext.getSharedPreferences( 1488 String.valueOf(WIDGET_ID_8), Context.MODE_PRIVATE); 1489 PeopleTileKey key8 = SharedPreferencesHelper.getPeopleTileKey(sp8); 1490 assertThat(key8.getShortcutId()).isNull(); 1491 assertThat(key8.getPackageName()).isNull(); 1492 1493 SharedPreferences sp11 = mContext.getSharedPreferences( 1494 String.valueOf(WIDGET_ID_11), Context.MODE_PRIVATE); 1495 PeopleTileKey key11 = SharedPreferencesHelper.getPeopleTileKey(sp11); 1496 assertThat(key11.getShortcutId()).isNull(); 1497 assertThat(key11.getPackageName()).isNull(); 1498 } 1499 1500 @Test testRemapWidgetFiles_crossMapping()1501 public void testRemapWidgetFiles_crossMapping() { 1502 setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_WITH_SHORTCUT, URI); 1503 setStorageForTile(OTHER_SHORTCUT_ID, TEST_PACKAGE_B, WIDGET_ID_WITHOUT_SHORTCUT, URI); 1504 setStorageForTile(THIRD_SHORTCUT_ID, TEST_PACKAGE_C, WIDGET_ID_WITH_KEY_IN_OPTIONS, URI); 1505 1506 mManager.remapWidgetFiles(WIDGETS_MAPPING_CROSS_MAPPING); 1507 1508 SharedPreferences sp1 = mContext.getSharedPreferences( 1509 String.valueOf(WIDGET_ID_WITH_SHORTCUT), Context.MODE_PRIVATE); 1510 PeopleTileKey key1 = SharedPreferencesHelper.getPeopleTileKey(sp1); 1511 assertThat(key1.getShortcutId()).isEqualTo(THIRD_SHORTCUT_ID); 1512 assertThat(key1.getPackageName()).isEqualTo(TEST_PACKAGE_C); 1513 1514 SharedPreferences sp2 = mContext.getSharedPreferences( 1515 String.valueOf(WIDGET_ID_WITHOUT_SHORTCUT), Context.MODE_PRIVATE); 1516 PeopleTileKey key2 = SharedPreferencesHelper.getPeopleTileKey(sp2); 1517 assertThat(key2.getShortcutId()).isEqualTo(OTHER_SHORTCUT_ID); 1518 assertThat(key2.getPackageName()).isEqualTo(TEST_PACKAGE_B); 1519 1520 SharedPreferences sp4 = mContext.getSharedPreferences( 1521 String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS), Context.MODE_PRIVATE); 1522 PeopleTileKey key4 = SharedPreferencesHelper.getPeopleTileKey(sp4); 1523 assertThat(key4.getShortcutId()).isEqualTo(SHORTCUT_ID); 1524 assertThat(key4.getPackageName()).isEqualTo(TEST_PACKAGE_A); 1525 } 1526 1527 @Test testRemapSharedFile()1528 public void testRemapSharedFile() { 1529 setStorageForTile(SHORTCUT_ID, TEST_PACKAGE_A, WIDGET_ID_8, URI); 1530 setStorageForTile(OTHER_SHORTCUT_ID, TEST_PACKAGE_B, WIDGET_ID_11, URI); 1531 1532 mManager.remapSharedFile(WIDGETS_MAPPING); 1533 1534 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); 1535 1536 assertThat(sp.getString(String.valueOf(WIDGET_ID_8), null)).isNull(); 1537 assertThat(sp.getString(String.valueOf(WIDGET_ID_11), null)).isNull(); 1538 assertThat(sp.getString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), null)) 1539 .isEqualTo(URI.toString()); 1540 assertThat(sp.getString(String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS), null)) 1541 .isEqualTo(URI.toString()); 1542 1543 assertThat(sp.getStringSet(URI.toString(), new HashSet<>())).containsExactly( 1544 String.valueOf(WIDGET_ID_WITH_SHORTCUT), 1545 String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS)); 1546 1547 PeopleTileKey key8 = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); 1548 assertThat(sp.getStringSet(key8.toString(), new HashSet<>())).containsExactly( 1549 String.valueOf(WIDGET_ID_WITH_SHORTCUT)); 1550 1551 PeopleTileKey key11 = new PeopleTileKey(OTHER_SHORTCUT_ID, 0, TEST_PACKAGE_B); 1552 assertThat(sp.getStringSet(key11.toString(), new HashSet<>())).containsExactly( 1553 String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS)); 1554 } 1555 1556 @Test testRemapFollowupFile()1557 public void testRemapFollowupFile() { 1558 PeopleTileKey key8 = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); 1559 PeopleTileKey key11 = new PeopleTileKey(OTHER_SHORTCUT_ID, 0, TEST_PACKAGE_B); 1560 Set<String> set8 = new HashSet<>(Collections.singleton(String.valueOf(WIDGET_ID_8))); 1561 Set<String> set11 = new HashSet<>(Collections.singleton(String.valueOf(WIDGET_ID_11))); 1562 1563 SharedPreferences followUp = mContext.getSharedPreferences( 1564 PeopleBackupFollowUpJob.SHARED_FOLLOW_UP, Context.MODE_PRIVATE); 1565 SharedPreferences.Editor followUpEditor = followUp.edit(); 1566 followUpEditor.putStringSet(key8.toString(), set8); 1567 followUpEditor.putStringSet(key11.toString(), set11); 1568 followUpEditor.apply(); 1569 1570 mManager.remapFollowupFile(WIDGETS_MAPPING); 1571 1572 assertThat(followUp.getStringSet(key8.toString(), new HashSet<>())).containsExactly( 1573 String.valueOf(WIDGET_ID_WITH_SHORTCUT)); 1574 assertThat(followUp.getStringSet(key11.toString(), new HashSet<>())).containsExactly( 1575 String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS)); 1576 } 1577 1578 @Test 1579 @DisableFlags({ 1580 android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS, 1581 android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL 1582 }) testUpdateGeneratedPreview_flagDisabled()1583 public void testUpdateGeneratedPreview_flagDisabled() { 1584 mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); 1585 verify(mAppWidgetManager, times(0)).setWidgetPreview(any(), anyInt(), any()); 1586 } 1587 1588 @Test 1589 @EnableFlags(android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS) 1590 @DisableFlags(android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL) testUpdateGeneratedPreview_userLocked()1591 public void testUpdateGeneratedPreview_userLocked() { 1592 when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(false); 1593 1594 mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); 1595 verify(mAppWidgetManager, times(0)).setWidgetPreview(any(), anyInt(), any()); 1596 } 1597 1598 @Test 1599 @EnableFlags(android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS) 1600 @DisableFlags(android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL) testUpdateGeneratedPreview_userUnlocked()1601 public void testUpdateGeneratedPreview_userUnlocked() { 1602 when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(true); 1603 when(mAppWidgetManager.setWidgetPreview(any(), anyInt(), any())).thenReturn(true); 1604 1605 mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); 1606 verify(mAppWidgetManager, times(1)).setWidgetPreview(any(), anyInt(), any()); 1607 } 1608 1609 @Test 1610 @EnableFlags(android.appwidget.flags.Flags.FLAG_GENERATED_PREVIEWS) 1611 @DisableFlags(android.appwidget.flags.Flags.FLAG_DRAW_DATA_PARCEL) testUpdateGeneratedPreview_doesNotSetTwice()1612 public void testUpdateGeneratedPreview_doesNotSetTwice() { 1613 when(mUserManager.isUserUnlocked(mUserTracker.getUserHandle())).thenReturn(true); 1614 when(mAppWidgetManager.setWidgetPreview(any(), anyInt(), any())).thenReturn(true); 1615 1616 mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); 1617 mManager.updateGeneratedPreviewForUser(mUserTracker.getUserHandle()); 1618 verify(mAppWidgetManager, times(1)).setWidgetPreview(any(), anyInt(), any()); 1619 } 1620 setFinalField(String fieldName, int value)1621 private void setFinalField(String fieldName, int value) { 1622 try { 1623 Field field = NotificationManager.Policy.class.getDeclaredField(fieldName); 1624 field.setAccessible(true); 1625 field.set(mNotificationPolicy, value); 1626 } catch (Exception e) { 1627 } 1628 } 1629 1630 /** 1631 * Adds another widget for {@code PERSON_TILE} with widget ID: {@code 1632 * SECOND_WIDGET_ID_WITH_SHORTCUT}. 1633 */ addSecondWidgetForPersonTile()1634 private void addSecondWidgetForPersonTile() throws Exception { 1635 // Set the same Person associated on another People Tile widget ID. 1636 addTileForWidget(PERSON_TILE, SECOND_WIDGET_ID_WITH_SHORTCUT); 1637 int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, 1638 SECOND_WIDGET_ID_WITH_SHORTCUT}; 1639 when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); 1640 } 1641 addTileForWidget(PeopleSpaceTile tile, int widgetId)1642 private void addTileForWidget(PeopleSpaceTile tile, int widgetId) throws Exception { 1643 setStorageForTile(tile.getId(), tile.getPackageName(), widgetId, tile.getContactUri()); 1644 Bundle options = new Bundle(); 1645 ConversationChannel channel = getConversationWithShortcutId(new PeopleTileKey(tile)); 1646 when(mAppWidgetManager.getAppWidgetOptions(eq(widgetId))) 1647 .thenReturn(options); 1648 when(mIPeopleManager.getConversation(tile.getPackageName(), 0, tile.getId())) 1649 .thenReturn(channel); 1650 when(mPackageManager.checkPermission(any(), eq(tile.getPackageName()))).thenReturn( 1651 PERMISSION_GRANTED); 1652 } 1653 1654 /** 1655 * Returns a single conversation associated with {@code shortcutId}. 1656 */ getConversationWithShortcutId(PeopleTileKey key)1657 private ConversationChannel getConversationWithShortcutId(PeopleTileKey key) throws Exception { 1658 return getConversationWithShortcutId(key, Arrays.asList()); 1659 } 1660 1661 /** 1662 * Returns a single conversation associated with {@code shortcutId} and {@code statuses}. 1663 */ getConversationWithShortcutId(PeopleTileKey key, List<ConversationStatus> statuses)1664 private ConversationChannel getConversationWithShortcutId(PeopleTileKey key, 1665 List<ConversationStatus> statuses) throws Exception { 1666 when(mMockContext.getPackageName()).thenReturn(key.getPackageName()); 1667 when(mMockContext.getUserId()).thenReturn(key.getUserId()); 1668 ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mMockContext, key.getShortcutId()) 1669 .setLongLabel("name").setPerson(PERSON).build(); 1670 ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null, 1671 0L, false, false, statuses); 1672 return convo; 1673 } 1674 createMessagingStyleNotification(String shortcutId, boolean isMessagingStyle, boolean isMissedCall)1675 private Notification createMessagingStyleNotification(String shortcutId, 1676 boolean isMessagingStyle, boolean isMissedCall) { 1677 Bundle extras = new Bundle(); 1678 ArrayList<Person> person = new ArrayList<Person>(); 1679 person.add(PERSON); 1680 extras.putParcelableArrayList(EXTRA_PEOPLE_LIST, person); 1681 Notification.Builder builder = new Notification.Builder(mContext) 1682 .setContentTitle("TEST_TITLE") 1683 .setContentText("TEST_TEXT") 1684 .setExtras(extras) 1685 .setShortcutId(shortcutId); 1686 if (isMessagingStyle) { 1687 builder.setStyle(new Notification.MessagingStyle(PERSON) 1688 .addMessage( 1689 new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT_1, 10, 1690 PERSON)) 1691 ); 1692 } 1693 if (isMissedCall) { 1694 builder.setCategory(CATEGORY_MISSED_CALL); 1695 } 1696 return builder.build(); 1697 } 1698 createMessagingStyleNotificationWithoutExtras(String shortcutId, boolean isMessagingStyle, boolean isMissedCall)1699 private Notification.Builder createMessagingStyleNotificationWithoutExtras(String shortcutId, 1700 boolean isMessagingStyle, boolean isMissedCall) { 1701 Notification.Builder builder = new Notification.Builder(mContext) 1702 .setContentTitle("TEST_TITLE") 1703 .setContentText("TEST_TEXT") 1704 .setShortcutId(shortcutId); 1705 if (isMessagingStyle) { 1706 builder.setStyle(new Notification.MessagingStyle(PERSON) 1707 .addMessage( 1708 new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT_1, 10, 1709 PERSON)) 1710 ); 1711 } 1712 if (isMissedCall) { 1713 builder.setCategory(CATEGORY_MISSED_CALL); 1714 } 1715 return builder; 1716 } 1717 1718 createNotification(String shortcutId, boolean isMessagingStyle, boolean isMissedCall)1719 private StatusBarNotification createNotification(String shortcutId, 1720 boolean isMessagingStyle, boolean isMissedCall) { 1721 Notification notification = createMessagingStyleNotification( 1722 shortcutId, isMessagingStyle, isMissedCall); 1723 return new SbnBuilder() 1724 .setNotification(notification) 1725 .setPkg(TEST_PACKAGE_A) 1726 .setUid(0) 1727 .setPostTime(SBN_POST_TIME) 1728 .setUser(new UserHandle(0)) 1729 .build(); 1730 } 1731 clearStorage()1732 private void clearStorage() { 1733 SharedPreferences widgetSp1 = mContext.getSharedPreferences( 1734 String.valueOf(WIDGET_ID_WITH_SHORTCUT), 1735 Context.MODE_PRIVATE); 1736 widgetSp1.edit().clear().commit(); 1737 SharedPreferences widgetSp2 = mContext.getSharedPreferences( 1738 String.valueOf(WIDGET_ID_WITHOUT_SHORTCUT), 1739 Context.MODE_PRIVATE); 1740 widgetSp2.edit().clear().commit(); 1741 SharedPreferences widgetSp3 = mContext.getSharedPreferences( 1742 String.valueOf(SECOND_WIDGET_ID_WITH_SHORTCUT), 1743 Context.MODE_PRIVATE); 1744 widgetSp3.edit().clear().commit(); 1745 SharedPreferences widgetSp4 = mContext.getSharedPreferences( 1746 String.valueOf(WIDGET_ID_WITH_KEY_IN_OPTIONS), 1747 Context.MODE_PRIVATE); 1748 widgetSp4.edit().clear().commit(); 1749 SharedPreferences widgetSp5 = mContext.getSharedPreferences( 1750 String.valueOf(WIDGET_ID_WITH_SAME_URI), 1751 Context.MODE_PRIVATE); 1752 widgetSp5.edit().clear().commit(); 1753 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); 1754 sp.edit().clear().commit(); 1755 mManager.mListeners.clear(); 1756 mManager.mTiles.clear(); 1757 } 1758 setStorageForTile(String shortcutId, String packageName, int widgetId, Uri contactUri)1759 private void setStorageForTile(String shortcutId, String packageName, int widgetId, 1760 Uri contactUri) { 1761 SharedPreferences widgetSp = mContext.getSharedPreferences( 1762 String.valueOf(widgetId), 1763 Context.MODE_PRIVATE); 1764 SharedPreferences.Editor widgetEditor = widgetSp.edit(); 1765 widgetEditor.putString(PeopleSpaceUtils.PACKAGE_NAME, packageName); 1766 widgetEditor.putString(PeopleSpaceUtils.SHORTCUT_ID, shortcutId); 1767 widgetEditor.putInt(PeopleSpaceUtils.USER_ID, 0); 1768 widgetEditor.apply(); 1769 1770 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); 1771 SharedPreferences.Editor editor = sp.edit(); 1772 editor.putString(String.valueOf(widgetId), contactUri.toString()); 1773 1774 String key = new PeopleTileKey(shortcutId, 0, packageName).toString(); 1775 Set<String> storedWidgetIds = new HashSet<>(sp.getStringSet(key, new HashSet<>())); 1776 storedWidgetIds.add(String.valueOf(widgetId)); 1777 editor.putStringSet(key, storedWidgetIds); 1778 1779 Set<String> storedWidgetIdsByUri = new HashSet<>( 1780 sp.getStringSet(contactUri.toString(), new HashSet<>())); 1781 storedWidgetIdsByUri.add(String.valueOf(widgetId)); 1782 editor.putStringSet(contactUri.toString(), storedWidgetIdsByUri); 1783 editor.apply(); 1784 } 1785 getConversationChannelWrapper(String shortcutId, boolean importantConversation, long lastInteractionTimestamp)1786 private ConversationChannelWrapper getConversationChannelWrapper(String shortcutId, 1787 boolean importantConversation, long lastInteractionTimestamp) throws Exception { 1788 ConversationChannelWrapper convo = new ConversationChannelWrapper(); 1789 NotificationChannel notificationChannel = new NotificationChannel(shortcutId, 1790 "channel" + shortcutId, 1791 NotificationManager.IMPORTANCE_DEFAULT); 1792 notificationChannel.setImportantConversation(importantConversation); 1793 convo.setNotificationChannel(notificationChannel); 1794 convo.setShortcutInfo(new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel( 1795 "name").build()); 1796 when(mIPeopleManager.getLastInteraction(anyString(), anyInt(), 1797 eq(shortcutId))).thenReturn(lastInteractionTimestamp); 1798 return convo; 1799 } 1800 getConversationChannel(String shortcutId, long lastInteractionTimestamp)1801 private ConversationChannel getConversationChannel(String shortcutId, 1802 long lastInteractionTimestamp) throws Exception { 1803 ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel( 1804 "name").build(); 1805 ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null, 1806 lastInteractionTimestamp, false); 1807 when(mIPeopleManager.getLastInteraction(anyString(), anyInt(), 1808 eq(shortcutId))).thenReturn(lastInteractionTimestamp); 1809 return convo; 1810 } 1811 } 1812