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.server.people.data;
18 
19 import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;
20 import static android.app.people.ConversationStatus.ACTIVITY_GAME;
21 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
22 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
23 import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
24 
25 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
26 
27 import static com.google.common.truth.Truth.assertThat;
28 
29 import static junit.framework.Assert.fail;
30 
31 import static org.junit.Assert.assertEquals;
32 import static org.junit.Assert.assertFalse;
33 import static org.junit.Assert.assertNotNull;
34 import static org.junit.Assert.assertNull;
35 import static org.junit.Assert.assertTrue;
36 import static org.mockito.ArgumentMatchers.any;
37 import static org.mockito.ArgumentMatchers.anyInt;
38 import static org.mockito.ArgumentMatchers.anyList;
39 import static org.mockito.ArgumentMatchers.anyLong;
40 import static org.mockito.ArgumentMatchers.anyString;
41 import static org.mockito.Mockito.doAnswer;
42 import static org.mockito.Mockito.eq;
43 import static org.mockito.Mockito.mock;
44 import static org.mockito.Mockito.never;
45 import static org.mockito.Mockito.times;
46 import static org.mockito.Mockito.verify;
47 import static org.mockito.Mockito.when;
48 
49 import android.annotation.NonNull;
50 import android.annotation.Nullable;
51 import android.annotation.UserIdInt;
52 import android.app.AlarmManager;
53 import android.app.Notification;
54 import android.app.NotificationChannel;
55 import android.app.NotificationManager;
56 import android.app.Person;
57 import android.app.job.JobScheduler;
58 import android.app.people.ConversationChannel;
59 import android.app.people.ConversationStatus;
60 import android.app.prediction.AppTarget;
61 import android.app.prediction.AppTargetEvent;
62 import android.app.prediction.AppTargetId;
63 import android.app.usage.UsageStatsManagerInternal;
64 import android.content.BroadcastReceiver;
65 import android.content.ContentResolver;
66 import android.content.Context;
67 import android.content.Intent;
68 import android.content.IntentFilter;
69 import android.content.pm.LauncherApps.ShortcutChangeCallback;
70 import android.content.pm.LauncherApps.ShortcutQuery;
71 import android.content.pm.PackageManager;
72 import android.content.pm.PackageManagerInternal;
73 import android.content.pm.ShortcutInfo;
74 import android.content.pm.ShortcutServiceInternal;
75 import android.content.pm.UserInfo;
76 import android.database.ContentObserver;
77 import android.net.Uri;
78 import android.os.CancellationSignal;
79 import android.os.Looper;
80 import android.os.UserHandle;
81 import android.os.UserManager;
82 import android.os.test.TestLooper;
83 import android.provider.ContactsContract;
84 import android.service.notification.NotificationListenerService;
85 import android.service.notification.StatusBarNotification;
86 import android.telecom.TelecomManager;
87 import android.telephony.TelephonyManager;
88 import android.text.format.DateUtils;
89 import android.util.Range;
90 
91 import com.android.internal.app.ChooserActivity;
92 import com.android.internal.content.PackageMonitor;
93 import com.android.server.LocalServices;
94 import com.android.server.notification.NotificationManagerInternal;
95 import com.android.server.people.PeopleService;
96 import com.android.server.pm.pkg.AndroidPackage;
97 
98 import com.google.common.collect.Iterables;
99 
100 import org.junit.After;
101 import org.junit.Before;
102 import org.junit.Test;
103 import org.junit.runner.RunWith;
104 import org.junit.runners.JUnit4;
105 import org.mockito.ArgumentCaptor;
106 import org.mockito.Captor;
107 import org.mockito.Mock;
108 import org.mockito.MockitoAnnotations;
109 
110 import java.util.ArrayList;
111 import java.util.Arrays;
112 import java.util.Collections;
113 import java.util.List;
114 import java.util.Set;
115 import java.util.concurrent.Executor;
116 import java.util.concurrent.ScheduledExecutorService;
117 import java.util.function.BiConsumer;
118 import java.util.function.Consumer;
119 import java.util.function.Function;
120 
121 @RunWith(JUnit4.class)
122 public final class DataManagerTest {
123 
124     private static final int USER_ID_PRIMARY = 0;
125     private static final int USER_ID_PRIMARY_MANAGED = 10;
126     private static final int USER_ID_SECONDARY = 11;
127     private static final String TEST_PKG_NAME = "pkg";
128     private static final String TEST_CLASS_NAME = "class";
129     private static final String TEST_SHORTCUT_ID = "sc";
130     private static final String TEST_SHORTCUT_ID_2 = "sc2";
131     private static final int TEST_PKG_UID = 35;
132     private static final String CONTACT_URI = "content://com.android.contacts/contacts/lookup/123";
133     private static final String PHONE_NUMBER = "+1234567890";
134     private static final String NOTIFICATION_CHANNEL_ID = "test : sc";
135     private static final String PARENT_NOTIFICATION_CHANNEL_ID = "test";
136     private static final long MILLIS_PER_MINUTE = 1000L * 60L;
137     private static final String GENERIC_KEY = "key";
138     private static final String CUSTOM_KEY = "custom";
139 
140     @Mock
141     private Context mContext;
142     @Mock
143     private ShortcutServiceInternal mShortcutServiceInternal;
144     @Mock
145     private UsageStatsManagerInternal mUsageStatsManagerInternal;
146     @Mock
147     private PackageManagerInternal mPackageManagerInternal;
148     @Mock
149     private NotificationManagerInternal mNotificationManagerInternal;
150     @Mock
151     private UserManager mUserManager;
152     @Mock
153     private PackageManager mPackageManager;
154     @Mock
155     private TelephonyManager mTelephonyManager;
156     @Mock
157     private TelecomManager mTelecomManager;
158     @Mock
159     private ContentResolver mContentResolver;
160     @Mock
161     private JobScheduler mJobScheduler;
162     @Mock
163     private StatusBarNotification mGenericSbn;
164     @Mock
165     private StatusBarNotification mConvoSbn;
166     @Mock
167     private NotificationListenerService.RankingMap mRankingMap;
168     @Mock
169     private Notification mNotification;
170     @Mock
171     private AlarmManager mAlarmManager;
172 
173     @Captor
174     private ArgumentCaptor<ShortcutChangeCallback> mShortcutChangeCallbackCaptor;
175     @Captor
176     private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
177     @Captor
178     private ArgumentCaptor<Integer> mQueryFlagsCaptor;
179 
180     private ScheduledExecutorService mExecutorService;
181     private NotificationChannel mNotificationChannel;
182     private NotificationChannel mParentNotificationChannel;
183     private DataManager mDataManager;
184     private CancellationSignal mCancellationSignal;
185     private ShortcutChangeCallback mShortcutChangeCallback;
186     private ShortcutInfo mShortcutInfo;
187     private TestInjector mInjector;
188     private TestLooper mLooper;
189 
190     @Before
setUp()191     public void setUp() throws PackageManager.NameNotFoundException {
192         MockitoAnnotations.initMocks(this);
193 
194         addLocalServiceMock(ShortcutServiceInternal.class, mShortcutServiceInternal);
195 
196         addLocalServiceMock(UsageStatsManagerInternal.class, mUsageStatsManagerInternal);
197 
198         addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternal);
199         AndroidPackage androidPackage = mock(AndroidPackage.class);
200         when(androidPackage.getPackageName()).thenReturn(TEST_PKG_NAME);
201         doAnswer(ans -> {
202             Consumer<AndroidPackage> callback = (Consumer<AndroidPackage>) ans.getArguments()[0];
203             callback.accept(androidPackage);
204             return null;
205         }).when(mPackageManagerInternal).forEachInstalledPackage(any(Consumer.class), anyInt());
206 
207         addLocalServiceMock(NotificationManagerInternal.class, mNotificationManagerInternal);
208         mParentNotificationChannel = new NotificationChannel(
209                 PARENT_NOTIFICATION_CHANNEL_ID, "test channel",
210                 NotificationManager.IMPORTANCE_DEFAULT);
211 
212         when(mContext.getContentResolver()).thenReturn(mContentResolver);
213         when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
214         when(mContext.getPackageName()).thenReturn("android");
215         when(mContext.getPackageManager()).thenReturn(mPackageManager);
216 
217         Context originalContext = getInstrumentation().getTargetContext();
218         when(mContext.getApplicationInfo()).thenReturn(originalContext.getApplicationInfo());
219         when(mContext.getUser()).thenReturn(originalContext.getUser());
220         when(mContext.getPackageName()).thenReturn(originalContext.getPackageName());
221 
222         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
223         when(mContext.getSystemServiceName(UserManager.class)).thenReturn(
224                 Context.USER_SERVICE);
225         when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
226         when(mContext.getSystemServiceName(AlarmManager.class)).thenReturn(
227                 Context.ALARM_SERVICE);
228 
229         when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
230 
231         when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager);
232         when(mContext.getSystemServiceName(TelecomManager.class)).thenReturn(
233                 Context.TELECOM_SERVICE);
234         when(mTelecomManager.getDefaultDialerPackage(any(UserHandle.class)))
235                 .thenReturn(TEST_PKG_NAME);
236 
237         when(mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE)).thenReturn(mJobScheduler);
238         when(mContext.getSystemServiceName(JobScheduler.class)).thenReturn(
239                 Context.JOB_SCHEDULER_SERVICE);
240 
241         mExecutorService = new MockScheduledExecutorService();
242 
243         when(mUserManager.getEnabledProfiles(USER_ID_PRIMARY))
244                 .thenReturn(Arrays.asList(
245                         buildUserInfo(USER_ID_PRIMARY),
246                         buildUserInfo(USER_ID_PRIMARY_MANAGED)));
247         when(mUserManager.getEnabledProfiles(USER_ID_SECONDARY))
248                 .thenReturn(Collections.singletonList(buildUserInfo(USER_ID_SECONDARY)));
249 
250         when(mPackageManager.getPackageUidAsUser(TEST_PKG_NAME, USER_ID_PRIMARY))
251                 .thenReturn(TEST_PKG_UID);
252 
253         mNotificationChannel = new NotificationChannel(
254                 NOTIFICATION_CHANNEL_ID, "test channel", NotificationManager.IMPORTANCE_DEFAULT);
255         mNotificationChannel.setConversationId(PARENT_NOTIFICATION_CHANNEL_ID, TEST_SHORTCUT_ID);
256         when(mNotificationManagerInternal.getNotificationChannel(anyString(), anyInt(),
257                 eq(mNotificationChannel.getId()))).thenReturn(mNotificationChannel);
258         when(mNotificationManagerInternal.getNotificationChannel(anyString(), anyInt(),
259                 eq(mParentNotificationChannel.getId()))).thenReturn(mParentNotificationChannel);
260 
261         when(mGenericSbn.getKey()).thenReturn(GENERIC_KEY);
262         when(mGenericSbn.getNotification()).thenReturn(mNotification);
263         when(mGenericSbn.getPackageName()).thenReturn(TEST_PKG_NAME);
264         when(mGenericSbn.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY));
265         when(mGenericSbn.getPostTime()).thenReturn(System.currentTimeMillis());
266         when(mConvoSbn.getKey()).thenReturn(CUSTOM_KEY);
267         when(mConvoSbn.getNotification()).thenReturn(mNotification);
268         when(mConvoSbn.getPackageName()).thenReturn(TEST_PKG_NAME);
269         when(mConvoSbn.getUser()).thenReturn(UserHandle.of(USER_ID_PRIMARY));
270         when(mConvoSbn.getPostTime()).thenReturn(System.currentTimeMillis());
271 
272         when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID);
273 
274         mCancellationSignal = new CancellationSignal();
275 
276         mInjector = new TestInjector();
277         mLooper = new TestLooper();
278         mDataManager = new DataManager(mContext, mInjector, mLooper.getLooper());
279         mDataManager.initialize();
280 
281         when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
282                 anyString(), anyInt(), any())).thenReturn(true);
283 
284         mShortcutInfo = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
285                 buildPerson());
286         when(mShortcutServiceInternal.getShortcuts(
287                 anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
288                 anyInt(), anyInt(), anyInt(), anyInt()))
289                 .thenReturn(Collections.singletonList(mShortcutInfo));
290         verify(mShortcutServiceInternal).addShortcutChangeCallback(
291                 mShortcutChangeCallbackCaptor.capture());
292         mShortcutChangeCallback = mShortcutChangeCallbackCaptor.getValue();
293 
294         verify(mContext, times(1)).registerReceiver(any(), any());
295         verify(mContext, times(1)).registerReceiver(any(), any(), anyInt());
296     }
297 
298     @After
tearDown()299     public void tearDown() {
300         LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
301         LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
302         LocalServices.removeServiceForTest(PackageManagerInternal.class);
303     }
304 
305     @Test
testAccessConversationFromTheSameProfileGroup()306     public void testAccessConversationFromTheSameProfileGroup() {
307         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
308         mDataManager.onUserUnlocked(USER_ID_PRIMARY_MANAGED);
309         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
310 
311         mDataManager.addOrUpdateConversationInfo(
312                 buildShortcutInfo("pkg_1", USER_ID_PRIMARY, "sc_1",
313                         buildPerson(true, false)));
314         mDataManager.addOrUpdateConversationInfo(
315                 buildShortcutInfo("pkg_2", USER_ID_PRIMARY_MANAGED, "sc_2",
316                         buildPerson(false, true)));
317         mDataManager.addOrUpdateConversationInfo(
318                 buildShortcutInfo("pkg_3", USER_ID_SECONDARY, "sc_3", buildPerson()));
319 
320         List<ConversationInfo> conversations = getConversationsInPrimary();
321 
322         // USER_ID_SECONDARY is not in the same profile group as USER_ID_PRIMARY.
323         assertEquals(2, conversations.size());
324 
325         assertEquals("sc_1", conversations.get(0).getShortcutId());
326         assertTrue(conversations.get(0).isPersonImportant());
327         assertFalse(conversations.get(0).isPersonBot());
328         assertFalse(conversations.get(0).isContactStarred());
329         assertEquals(PHONE_NUMBER, conversations.get(0).getContactPhoneNumber());
330 
331         assertEquals("sc_2", conversations.get(1).getShortcutId());
332         assertFalse(conversations.get(1).isPersonImportant());
333         assertTrue(conversations.get(1).isPersonBot());
334         assertFalse(conversations.get(0).isContactStarred());
335         assertEquals(PHONE_NUMBER, conversations.get(0).getContactPhoneNumber());
336     }
337 
338     @Test
testAccessConversationForUnlockedUsersOnly()339     public void testAccessConversationForUnlockedUsersOnly() {
340         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
341         mDataManager.addOrUpdateConversationInfo(
342                 buildShortcutInfo("pkg_1", USER_ID_PRIMARY, "sc_1", buildPerson()));
343         mDataManager.addOrUpdateConversationInfo(
344                 buildShortcutInfo("pkg_2", USER_ID_PRIMARY_MANAGED, "sc_2", buildPerson()));
345 
346         List<ConversationInfo> conversations = getConversationsInPrimary();
347 
348         // USER_ID_PRIMARY_MANAGED is not locked, so only USER_ID_PRIMARY's conversation is stored.
349         assertEquals(1, conversations.size());
350         assertEquals("sc_1", conversations.get(0).getShortcutId());
351 
352         mDataManager.onUserStopping(USER_ID_PRIMARY);
353         conversations = getConversationsInPrimary();
354         assertTrue(conversations.isEmpty());
355     }
356 
357     @Test
testGetShortcut()358     public void testGetShortcut() {
359         mDataManager.getShortcut(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID);
360         verify(mShortcutServiceInternal).getShortcuts(anyInt(), anyString(), anyLong(),
361                 eq(TEST_PKG_NAME), eq(Collections.singletonList(TEST_SHORTCUT_ID)),
362                 eq(null), eq(null), anyInt(), eq(USER_ID_PRIMARY), anyInt(), anyInt());
363     }
364 
365     @Test
testReportAppTargetEvent_directSharing()366     public void testReportAppTargetEvent_directSharing()
367             throws IntentFilter.MalformedMimeTypeException {
368         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
369         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
370                 buildPerson());
371         mDataManager.addOrUpdateConversationInfo(shortcut);
372 
373         AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut)
374                 .build();
375         AppTargetEvent appTargetEvent =
376                 new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
377                         .setLaunchLocation(ChooserActivity.LAUNCH_LOCATION_DIRECT_SHARE)
378                         .build();
379         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
380         mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
381 
382         List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
383                 Event.SHARE_EVENT_TYPES);
384         assertEquals(1, activeShareTimeSlots.size());
385     }
386 
387     @Test
testReportAppTargetEvent_directSharing_createConversation()388     public void testReportAppTargetEvent_directSharing_createConversation()
389             throws IntentFilter.MalformedMimeTypeException {
390         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
391         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
392                 null);
393         AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut)
394                 .build();
395         AppTargetEvent appTargetEvent =
396                 new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
397                         .setLaunchLocation(ChooserActivity.LAUNCH_LOCATION_DIRECT_SHARE)
398                         .build();
399         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
400 
401         mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
402 
403         List<Range<Long>> activeShareTimeSlots = getActiveSlotsForTestShortcut(
404                 Event.SHARE_EVENT_TYPES);
405         assertEquals(1, activeShareTimeSlots.size());
406         ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
407                 .getConversationStore()
408                 .getConversation(TEST_SHORTCUT_ID);
409         assertNotNull(conversationInfo);
410         assertEquals(conversationInfo.getShortcutId(), TEST_SHORTCUT_ID);
411     }
412 
413     @Test
testReportAppTargetEvent_appSharing()414     public void testReportAppTargetEvent_appSharing()
415             throws IntentFilter.MalformedMimeTypeException {
416         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
417         AppTarget appTarget = new AppTarget.Builder(
418                 new AppTargetId(TEST_SHORTCUT_ID),
419                 TEST_PKG_NAME,
420                 UserHandle.of(USER_ID_PRIMARY))
421                 .setClassName(TEST_CLASS_NAME)
422                 .build();
423         AppTargetEvent appTargetEvent =
424                 new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
425                         .build();
426         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
427 
428         mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
429 
430         List<Range<Long>> activeShareTimeSlots = getActiveSlotsForAppShares();
431         assertEquals(1, activeShareTimeSlots.size());
432     }
433 
434     @Test
testContactsChanged()435     public void testContactsChanged() {
436         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
437         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
438 
439         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
440                 buildPerson());
441         mDataManager.addOrUpdateConversationInfo(shortcut);
442 
443         final String newPhoneNumber = "+1000000000";
444         mInjector.mContactsQueryHelper.mIsStarred = true;
445         mInjector.mContactsQueryHelper.mPhoneNumber = newPhoneNumber;
446 
447         ContentObserver contentObserver = mDataManager.getContactsContentObserverForTesting(
448                 USER_ID_PRIMARY);
449         contentObserver.onChange(false, ContactsContract.Contacts.CONTENT_URI, USER_ID_PRIMARY);
450 
451         List<ConversationInfo> conversations = getConversationsInPrimary();
452         assertEquals(1, conversations.size());
453 
454         assertEquals(TEST_SHORTCUT_ID, conversations.get(0).getShortcutId());
455         assertTrue(conversations.get(0).isContactStarred());
456         assertEquals(newPhoneNumber, conversations.get(0).getContactPhoneNumber());
457     }
458 
459     @Test
testNotificationPosted()460     public void testNotificationPosted() {
461         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
462 
463         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
464                 buildPerson());
465         mDataManager.addOrUpdateConversationInfo(shortcut);
466 
467         sendGenericNotification();
468 
469         List<Range<Long>> activeNotificationOpenTimeSlots = getActiveSlotsForTestShortcut(
470                 Event.NOTIFICATION_EVENT_TYPES);
471         assertEquals(1, activeNotificationOpenTimeSlots.size());
472     }
473 
474     @Test
testNotificationOpened()475     public void testNotificationOpened() {
476         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
477 
478         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
479                 buildPerson());
480         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
481         mDataManager.addOrUpdateConversationInfo(shortcut);
482 
483         NotificationListenerService listenerService =
484                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
485 
486         listenerService.onNotificationRemoved(mGenericSbn, null,
487                 NotificationListenerService.REASON_CLICK);
488 
489         List<Range<Long>> activeNotificationOpenTimeSlots = getActiveSlotsForTestShortcut(
490                 Event.NOTIFICATION_EVENT_TYPES);
491         assertEquals(1, activeNotificationOpenTimeSlots.size());
492     }
493 
494     @Test
testUncacheShortcutsWhenNotificationsDismissed()495     public void testUncacheShortcutsWhenNotificationsDismissed() {
496         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
497         NotificationListenerService listenerService =
498                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
499 
500         // The cached conversations are above the limit because every conversation has active
501         // notifications. To uncache one of them, the notifications for that conversation need to
502         // be dismissed.
503         String notificationKey = "";
504         for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
505             String shortcutId = TEST_SHORTCUT_ID + i;
506             ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
507                     buildPerson());
508             shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
509             mDataManager.addOrUpdateConversationInfo(shortcut);
510             when(mNotification.getShortcutId()).thenReturn(shortcutId);
511             notificationKey = String.format("notification-key-%d", i);
512             sendGenericNotificationWithKey(notificationKey);
513         }
514 
515         // Post another notification for the last conversation.
516         String otherNotificationKey = "other-notification-key";
517         sendGenericNotificationWithKey(otherNotificationKey);
518 
519         // Removing one of the two notifications does not un-cache the shortcut.
520         listenerService.onNotificationRemoved(mGenericSbn, null,
521                 NotificationListenerService.REASON_CANCEL);
522         verify(mShortcutServiceInternal, never()).uncacheShortcuts(
523                 anyInt(), any(), anyString(), any(), anyInt(), anyInt());
524 
525         // Removing the second notification un-caches the shortcut.
526         when(mGenericSbn.getKey()).thenReturn(notificationKey);
527         listenerService.onNotificationRemoved(mGenericSbn, null,
528                 NotificationListenerService.REASON_CANCEL_ALL);
529         verify(mShortcutServiceInternal).uncacheShortcuts(
530                 anyInt(), any(), eq(TEST_PKG_NAME), anyList(), eq(USER_ID_PRIMARY),
531                 eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
532     }
533 
534     @Test
testConversationIsNotRecentIfCustomized()535     public void testConversationIsNotRecentIfCustomized() {
536         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
537 
538         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
539                 buildPerson());
540         mDataManager.addOrUpdateConversationInfo(shortcut);
541 
542         NotificationListenerService listenerService =
543                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
544 
545         sendGenericNotification();
546         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
547         mDataManager.addOrUpdateConversationInfo(shortcut);
548 
549         assertEquals(1, mDataManager.getRecentConversations(USER_ID_PRIMARY).size());
550 
551         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
552                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
553 
554         assertTrue(mDataManager.getRecentConversations(USER_ID_PRIMARY).isEmpty());
555     }
556 
557     @Test
testAddConversationsListener()558     public void testAddConversationsListener() throws Exception {
559         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
560         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
561                 buildPerson());
562         mDataManager.addOrUpdateConversationInfo(shortcut);
563         ConversationChannel conversationChannel = mDataManager.getConversation(TEST_PKG_NAME,
564                 USER_ID_PRIMARY,
565                 TEST_SHORTCUT_ID);
566 
567         PeopleService.ConversationsListener listener = mock(
568                 PeopleService.ConversationsListener.class);
569         mDataManager.addConversationsListener(listener);
570 
571         List<ConversationChannel> changedConversations = Arrays.asList(conversationChannel);
572         verify(listener, times(0)).onConversationsUpdate(eq(changedConversations));
573         mDataManager.notifyConversationsListeners(changedConversations);
574         mLooper.dispatchAll();
575 
576         verify(listener, times(1)).onConversationsUpdate(eq(changedConversations));
577     }
578 
579     @Test
testAddConversationListenersNotifiesMultipleConversations()580     public void testAddConversationListenersNotifiesMultipleConversations() throws Exception {
581         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
582         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
583                 buildPerson());
584         mDataManager.addOrUpdateConversationInfo(shortcut);
585         ConversationChannel conversationChannel = mDataManager.getConversation(TEST_PKG_NAME,
586                 USER_ID_PRIMARY,
587                 TEST_SHORTCUT_ID);
588         ShortcutInfo shortcut2 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY,
589                 TEST_SHORTCUT_ID_2,
590                 buildPerson());
591         mDataManager.addOrUpdateConversationInfo(shortcut2);
592         mLooper.dispatchAll();
593         ConversationChannel conversationChannel2 = mDataManager.getConversation(TEST_PKG_NAME,
594                 USER_ID_PRIMARY,
595                 TEST_SHORTCUT_ID_2);
596         PeopleService.ConversationsListener listener = mock(
597                 PeopleService.ConversationsListener.class);
598         mDataManager.addConversationsListener(listener);
599 
600         List<ConversationChannel> changedConversations = Arrays.asList(conversationChannel,
601                 conversationChannel2);
602         verify(listener, times(0)).onConversationsUpdate(eq(changedConversations));
603         mDataManager.notifyConversationsListeners(changedConversations);
604         mLooper.dispatchAll();
605 
606         verify(listener, times(1)).onConversationsUpdate(eq(changedConversations));
607         ArgumentCaptor<List<ConversationChannel>> capturedConversation = ArgumentCaptor.forClass(
608                 List.class);
609         verify(listener, times(1)).onConversationsUpdate(capturedConversation.capture());
610         assertThat(capturedConversation.getValue()).containsExactly(conversationChannel,
611                 conversationChannel2);
612     }
613 
614     @Test
testAddOrUpdateStatusNotifiesConversationsListeners()615     public void testAddOrUpdateStatusNotifiesConversationsListeners() throws Exception {
616         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
617         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
618                 buildPerson());
619         mDataManager.addOrUpdateConversationInfo(shortcut);
620         mLooper.dispatchAll();
621         PeopleService.ConversationsListener listener = mock(
622                 PeopleService.ConversationsListener.class);
623         mDataManager.addConversationsListener(listener);
624 
625         ConversationStatus status = new ConversationStatus.Builder("cs1", ACTIVITY_GAME).build();
626         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, status);
627         mLooper.dispatchAll();
628 
629         ArgumentCaptor<List<ConversationChannel>> capturedConversation = ArgumentCaptor.forClass(
630                 List.class);
631         verify(listener, times(1)).onConversationsUpdate(capturedConversation.capture());
632         ConversationChannel result = Iterables.getOnlyElement(capturedConversation.getValue());
633         assertThat(result.getStatuses()).containsExactly(status);
634         assertEquals(result.getShortcutInfo().getId(), TEST_SHORTCUT_ID);
635     }
636 
637     @Test
testGetConversationReturnsCustomizedConversation()638     public void testGetConversationReturnsCustomizedConversation() {
639         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
640 
641         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
642                 buildPerson());
643         mDataManager.addOrUpdateConversationInfo(shortcut);
644 
645         sendConvoNotification();
646         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
647         mDataManager.addOrUpdateConversationInfo(shortcut);
648 
649         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
650                 TEST_SHORTCUT_ID)).isNotNull();
651 
652         ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
653                 TEST_SHORTCUT_ID);
654         assertThat(result).isNotNull();
655         assertThat(result.hasBirthdayToday()).isFalse();
656         assertThat(result.getStatuses()).isEmpty();
657     }
658 
659     @Test
testGetConversation()660     public void testGetConversation() {
661         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
662         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
663                 TEST_SHORTCUT_ID)).isNull();
664 
665         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
666                 buildPerson());
667         shortcut.setCached(ShortcutInfo.FLAG_PINNED);
668         mDataManager.addOrUpdateConversationInfo(shortcut);
669         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
670                 TEST_SHORTCUT_ID)).isNotNull();
671         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
672                 TEST_SHORTCUT_ID + "1")).isNull();
673 
674         sendConvoNotification();
675         ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
676         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
677 
678         ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
679                 TEST_SHORTCUT_ID);
680         assertThat(result).isNotNull();
681         assertEquals(shortcut.getId(), result.getShortcutInfo().getId());
682         assertEquals(1, result.getShortcutInfo().getPersons().length);
683         assertEquals(CONTACT_URI, result.getShortcutInfo().getPersons()[0].getUri());
684         assertEquals(mNotificationChannel.getId(), result.getNotificationChannel().getId());
685         assertEquals(mParentNotificationChannel.getId(),
686                 result.getNotificationChannel().getParentChannelId());
687         assertEquals(mConvoSbn.getPostTime(), result.getLastEventTimestamp());
688         assertTrue(result.hasActiveNotifications());
689         assertFalse(result.hasBirthdayToday());
690         assertThat(result.getStatuses()).containsExactly(cs);
691     }
692 
693     @Test
testGetConversation_trackActiveConversations()694     public void testGetConversation_trackActiveConversations() {
695         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
696         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
697                 TEST_SHORTCUT_ID)).isNull();
698         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
699                 buildPerson());
700         shortcut.setCached(ShortcutInfo.FLAG_PINNED);
701         mDataManager.addOrUpdateConversationInfo(shortcut);
702         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
703                 TEST_SHORTCUT_ID)).isNotNull();
704 
705         sendGenericNotification();
706         sendGenericNotification();
707         ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
708                 TEST_SHORTCUT_ID);
709         assertTrue(result.hasActiveNotifications());
710 
711         // Both generic notifications have the same notification key, so a single dismiss will
712         // remove both of them.
713         NotificationListenerService listenerService =
714                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
715         listenerService.onNotificationRemoved(mGenericSbn, null,
716                 NotificationListenerService.REASON_CANCEL);
717         ConversationChannel resultTwo = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
718                 TEST_SHORTCUT_ID);
719         assertFalse(resultTwo.hasActiveNotifications());
720     }
721 
722     @Test
testGetConversation_unsyncedShortcut()723     public void testGetConversation_unsyncedShortcut() {
724         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
725         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
726                 buildPerson());
727         shortcut.setCached(ShortcutInfo.FLAG_PINNED);
728         mDataManager.addOrUpdateConversationInfo(shortcut);
729         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
730                 TEST_SHORTCUT_ID)).isNotNull();
731         assertThat(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
732                 .getConversationStore()
733                 .getConversation(TEST_SHORTCUT_ID)).isNotNull();
734 
735         when(mShortcutServiceInternal.getShortcuts(
736                 anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
737                 anyInt(), anyInt(), anyInt(), anyInt()))
738                 .thenReturn(Collections.emptyList());
739         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
740                 TEST_SHORTCUT_ID)).isNull();
741 
742         // Conversation is removed from store as there is no matching shortcut in ShortcutManager
743         assertThat(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
744                 .getConversationStore()
745                 .getConversation(TEST_SHORTCUT_ID)).isNull();
746         verify(mNotificationManagerInternal)
747                 .onConversationRemoved(TEST_PKG_NAME, TEST_PKG_UID, Set.of(TEST_SHORTCUT_ID));
748     }
749 
750     @Test
testOnNotificationChannelModified()751     public void testOnNotificationChannelModified() {
752         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
753         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
754                 TEST_SHORTCUT_ID)).isNull();
755 
756         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
757                 buildPerson());
758         shortcut.setCached(ShortcutInfo.FLAG_PINNED);
759         mDataManager.addOrUpdateConversationInfo(shortcut);
760 
761         sendConvoNotification();
762 
763         ConversationChannel result = mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
764                 TEST_SHORTCUT_ID);
765         assertFalse(result.getNotificationChannel().canBubble());
766 
767         NotificationChannel updated = new NotificationChannel(mNotificationChannel.getId(),
768                 mNotificationChannel.getDescription(), mNotificationChannel.getImportance());
769         updated.setConversationId(mNotificationChannel.getParentChannelId(),
770                 mNotificationChannel.getConversationId());
771         updated.setAllowBubbles(true);
772         NotificationListenerService listenerService =
773                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
774         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
775                 updated, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
776 
777         ConversationInfo ci = mDataManager.getConversationInfo(TEST_PKG_NAME, USER_ID_PRIMARY,
778                 TEST_SHORTCUT_ID);
779         assertThat(ci).isNotNull();
780         assertEquals(mNotificationChannel.getId(), ci.getNotificationChannelId());
781         assertEquals(mParentNotificationChannel.getId(), ci.getParentNotificationChannelId());
782         assertTrue(ci.isBubbled());
783     }
784 
785     @Test
testGetConversation_demoted()786     public void testGetConversation_demoted() {
787         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
788         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
789                 TEST_SHORTCUT_ID)).isNull();
790 
791         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
792                 buildPerson());
793         shortcut.setCached(ShortcutInfo.FLAG_PINNED);
794         mDataManager.addOrUpdateConversationInfo(shortcut);
795         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
796                 TEST_SHORTCUT_ID)).isNotNull();
797 
798         mNotificationChannel.setDemoted(true);
799         NotificationListenerService listenerService =
800                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
801         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
802                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
803 
804         assertThat(mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
805                 TEST_SHORTCUT_ID)).isNull();
806     }
807 
808     @Test
testGetConversationGetsPersonsData()809     public void testGetConversationGetsPersonsData() {
810         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
811 
812         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
813                 buildPerson());
814         shortcut.setCached(ShortcutInfo.FLAG_PINNED);
815         mDataManager.addOrUpdateConversationInfo(shortcut);
816 
817         sendGenericNotification();
818         mDataManager.getConversation(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID);
819 
820         verify(mShortcutServiceInternal).getShortcuts(
821                 anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
822                 mQueryFlagsCaptor.capture(), anyInt(), anyInt(), anyInt());
823         Integer queryFlags = mQueryFlagsCaptor.getValue();
824         assertThat(hasFlag(queryFlags, ShortcutQuery.FLAG_GET_PERSONS_DATA)).isTrue();
825     }
826 
827     @Test
testIsConversation()828     public void testIsConversation() {
829         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
830         assertThat(mDataManager.isConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
831                 TEST_SHORTCUT_ID)).isFalse();
832 
833         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
834                 buildPerson());
835         shortcut.setCached(ShortcutInfo.FLAG_PINNED);
836         mDataManager.addOrUpdateConversationInfo(shortcut);
837         assertThat(mDataManager.isConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
838                 TEST_SHORTCUT_ID)).isTrue();
839         assertThat(mDataManager.isConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
840                 TEST_SHORTCUT_ID + "1")).isFalse();
841     }
842 
843     @Test
testIsConversation_demoted()844     public void testIsConversation_demoted() {
845         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
846         assertThat(mDataManager.isConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
847                 TEST_SHORTCUT_ID)).isFalse();
848 
849         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
850                 buildPerson());
851         shortcut.setCached(ShortcutInfo.FLAG_PINNED);
852         mDataManager.addOrUpdateConversationInfo(shortcut);
853 
854         mNotificationChannel.setDemoted(true);
855         NotificationListenerService listenerService =
856                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
857         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
858                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
859 
860         assertThat(mDataManager.isConversation(TEST_PKG_NAME, USER_ID_PRIMARY,
861                 TEST_SHORTCUT_ID)).isFalse();
862     }
863 
864     @Test
testNotificationChannelCreated()865     public void testNotificationChannelCreated() {
866         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
867         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
868 
869         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
870                 buildPerson());
871         mDataManager.addOrUpdateConversationInfo(shortcut);
872 
873         NotificationListenerService listenerService =
874                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
875         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
876                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
877 
878         ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
879                 .getConversationStore()
880                 .getConversation(TEST_SHORTCUT_ID);
881         assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
882         assertFalse(conversationInfo.isImportant());
883         assertFalse(conversationInfo.isNotificationSilenced());
884         assertFalse(conversationInfo.isDemoted());
885     }
886 
887     @Test
testNotificationChannelModified()888     public void testNotificationChannelModified() {
889         mNotificationChannel.setImportantConversation(true);
890 
891         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
892         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
893 
894         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
895                 buildPerson());
896         mDataManager.addOrUpdateConversationInfo(shortcut);
897 
898         NotificationListenerService listenerService =
899                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
900         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
901                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
902 
903         ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
904                 .getConversationStore()
905                 .getConversation(TEST_SHORTCUT_ID);
906         assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
907         assertTrue(conversationInfo.isImportant());
908         assertFalse(conversationInfo.isNotificationSilenced());
909         assertFalse(conversationInfo.isDemoted());
910     }
911 
912     @Test
testNotificationChannelDeleted()913     public void testNotificationChannelDeleted() {
914         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
915         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
916 
917         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
918                 buildPerson());
919         mDataManager.addOrUpdateConversationInfo(shortcut);
920 
921         NotificationListenerService listenerService =
922                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
923         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
924                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
925         ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
926                 .getConversationStore()
927                 .getConversation(TEST_SHORTCUT_ID);
928         assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId());
929 
930         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
931                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
932         conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
933                 .getConversationStore()
934                 .getConversation(TEST_SHORTCUT_ID);
935         assertNull(conversationInfo.getNotificationChannelId());
936         assertFalse(conversationInfo.isImportant());
937         assertFalse(conversationInfo.isNotificationSilenced());
938         assertFalse(conversationInfo.isDemoted());
939     }
940 
941     @Test
testShortcutAddedOrUpdated()942     public void testShortcutAddedOrUpdated() {
943         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
944         PeopleService.ConversationsListener listener = mock(
945                 PeopleService.ConversationsListener.class);
946         mDataManager.addConversationsListener(listener);
947 
948         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
949                 buildPerson());
950         mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME,
951                 Collections.singletonList(shortcut), UserHandle.of(USER_ID_PRIMARY));
952         mLooper.dispatchAll();
953 
954         List<ConversationInfo> conversations = getConversationsInPrimary();
955 
956         assertEquals(1, conversations.size());
957         assertEquals(TEST_SHORTCUT_ID, conversations.get(0).getShortcutId());
958         ArgumentCaptor<List<ConversationChannel>> capturedConversation = ArgumentCaptor.forClass(
959                 List.class);
960         verify(listener, times(1)).onConversationsUpdate(capturedConversation.capture());
961         ConversationChannel result = Iterables.getOnlyElement(capturedConversation.getValue());
962         assertEquals(result.getShortcutInfo().getId(), TEST_SHORTCUT_ID);
963     }
964 
965     @Test
testShortcutsDeleted()966     public void testShortcutsDeleted() {
967         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
968 
969         ShortcutInfo shortcut1 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc1",
970                 buildPerson());
971         ShortcutInfo shortcut2 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc2",
972                 buildPerson());
973         ShortcutInfo shortcut3 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "sc3",
974                 buildPerson());
975         mShortcutChangeCallback.onShortcutsAddedOrUpdated(TEST_PKG_NAME,
976                 Arrays.asList(shortcut1, shortcut2, shortcut3), UserHandle.of(USER_ID_PRIMARY));
977         mShortcutChangeCallback.onShortcutsRemoved(TEST_PKG_NAME,
978                 List.of(shortcut1, shortcut3), UserHandle.of(USER_ID_PRIMARY));
979 
980         List<ConversationInfo> conversations = getConversationsInPrimary();
981 
982         assertEquals(1, conversations.size());
983         assertEquals("sc2", conversations.get(0).getShortcutId());
984 
985         verify(mNotificationManagerInternal)
986                 .onConversationRemoved(TEST_PKG_NAME, TEST_PKG_UID, Set.of("sc1", "sc3"));
987     }
988 
989     @Test
testCallLogContentObserver()990     public void testCallLogContentObserver() {
991         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
992         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
993 
994         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
995                 buildPerson());
996         mDataManager.addOrUpdateConversationInfo(shortcut);
997 
998         ContentObserver contentObserver = mDataManager.getCallLogContentObserverForTesting();
999         contentObserver.onChange(false);
1000         long currentTimestamp = System.currentTimeMillis();
1001         mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
1002                 new Event(currentTimestamp - MILLIS_PER_MINUTE * 15L, Event.TYPE_CALL_OUTGOING));
1003         mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
1004                 new Event(currentTimestamp - MILLIS_PER_MINUTE * 10L, Event.TYPE_CALL_INCOMING));
1005         mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
1006                 new Event(currentTimestamp - MILLIS_PER_MINUTE * 5L, Event.TYPE_CALL_MISSED));
1007 
1008         List<Range<Long>> activeTimeSlots = getActiveSlotsForTestShortcut(Event.CALL_EVENT_TYPES);
1009         assertEquals(3, activeTimeSlots.size());
1010     }
1011 
1012     @Test
testMmsSmsContentObserver()1013     public void testMmsSmsContentObserver() {
1014         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1015         mDataManager.onUserUnlocked(USER_ID_SECONDARY);
1016 
1017         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1018                 buildPerson());
1019         mDataManager.addOrUpdateConversationInfo(shortcut);
1020         mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(TEST_PKG_NAME);
1021 
1022         ContentObserver contentObserver = mDataManager.getMmsSmsContentObserverForTesting();
1023         contentObserver.onChange(false);
1024         long currentTimestamp = System.currentTimeMillis();
1025         Event outgoingSmsEvent =
1026                 new Event(currentTimestamp - MILLIS_PER_MINUTE * 10L, Event.TYPE_SMS_OUTGOING);
1027         Event incomingSmsEvent =
1028                 new Event(currentTimestamp - MILLIS_PER_MINUTE * 5L, Event.TYPE_SMS_INCOMING);
1029         mInjector.mMmsQueryHelper.mEventConsumer.accept(PHONE_NUMBER, outgoingSmsEvent);
1030         mInjector.mSmsQueryHelper.mEventConsumer.accept(PHONE_NUMBER, incomingSmsEvent);
1031 
1032         List<Range<Long>> activeTimeSlots = getActiveSlotsForTestShortcut(Event.SMS_EVENT_TYPES);
1033         assertEquals(2, activeTimeSlots.size());
1034     }
1035 
1036     @Test
testConversationLastEventTimestampUpdate()1037     public void testConversationLastEventTimestampUpdate() {
1038         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1039 
1040         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1041                 buildPerson());
1042         mDataManager.addOrUpdateConversationInfo(shortcut);
1043 
1044         PackageData packageData = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY);
1045         ConversationInfo conversationInfo =
1046                 packageData.getConversationStore().getConversation(TEST_SHORTCUT_ID);
1047         Event event = new Event(123L, Event.TYPE_IN_APP_CONVERSATION);
1048 
1049         mInjector.mUsageStatsQueryHelper.mEventListener.onEvent(packageData, conversationInfo,
1050                 event);
1051         ConversationInfo newConversationInfo =
1052                 packageData.getConversationStore().getConversation(TEST_SHORTCUT_ID);
1053         assertEquals(123L, newConversationInfo.getLastEventTimestamp());
1054     }
1055 
1056     @Test
testDeleteUninstalledPackageDataOnPackageRemoved()1057     public void testDeleteUninstalledPackageDataOnPackageRemoved() {
1058         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1059 
1060         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1061                 buildPerson());
1062         mDataManager.addOrUpdateConversationInfo(shortcut);
1063         assertNotNull(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY));
1064 
1065         PackageMonitor packageMonitor = mDataManager.getPackageMonitorForTesting(USER_ID_PRIMARY);
1066         Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED);
1067         intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_PRIMARY);
1068         intent.setData(Uri.parse("package:" + TEST_PKG_NAME));
1069         packageMonitor.onReceive(mContext, intent);
1070         assertNull(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY));
1071     }
1072 
1073     @Test
testPruneUninstalledPackageData()1074     public void testPruneUninstalledPackageData() {
1075         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1076 
1077         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1078                 buildPerson());
1079         mDataManager.addOrUpdateConversationInfo(shortcut);
1080         assertNotNull(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY));
1081 
1082         doAnswer(ans -> null).when(mPackageManagerInternal)
1083                 .forEachInstalledPackage(any(Consumer.class), anyInt());
1084         mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
1085         assertNull(mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY));
1086     }
1087 
1088     @Test
testPruneCallEventsFromNonDialer()1089     public void testPruneCallEventsFromNonDialer() {
1090         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1091 
1092         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1093                 buildPerson());
1094         mDataManager.addOrUpdateConversationInfo(shortcut);
1095 
1096         long currentTimestamp = System.currentTimeMillis();
1097         mInjector.mCallLogQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
1098                 new Event(currentTimestamp - MILLIS_PER_MINUTE, Event.TYPE_CALL_OUTGOING));
1099 
1100         List<Range<Long>> activeTimeSlots = getActiveSlotsForTestShortcut(Event.CALL_EVENT_TYPES);
1101         assertEquals(1, activeTimeSlots.size());
1102 
1103         mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultDialer(null);
1104         mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
1105         activeTimeSlots = getActiveSlotsForTestShortcut(Event.CALL_EVENT_TYPES);
1106         assertTrue(activeTimeSlots.isEmpty());
1107     }
1108 
1109     @Test
testPruneSmsEventsFromNonDefaultSmsApp()1110     public void testPruneSmsEventsFromNonDefaultSmsApp() {
1111         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1112 
1113         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1114                 buildPerson());
1115         mDataManager.addOrUpdateConversationInfo(shortcut);
1116         mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(TEST_PKG_NAME);
1117 
1118         long currentTimestamp = System.currentTimeMillis();
1119         mInjector.mMmsQueryHelper.mEventConsumer.accept(PHONE_NUMBER,
1120                 new Event(currentTimestamp - MILLIS_PER_MINUTE, Event.TYPE_SMS_OUTGOING));
1121 
1122         List<Range<Long>> activeTimeSlots = getActiveSlotsForTestShortcut(Event.SMS_EVENT_TYPES);
1123         assertEquals(1, activeTimeSlots.size());
1124 
1125         mDataManager.getUserDataForTesting(USER_ID_PRIMARY).setDefaultSmsApp(null);
1126         mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
1127         activeTimeSlots = getActiveSlotsForTestShortcut(Event.SMS_EVENT_TYPES);
1128         assertTrue(activeTimeSlots.isEmpty());
1129     }
1130 
1131     @Test
testPruneExpiredConversationStatuses()1132     public void testPruneExpiredConversationStatuses() {
1133         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1134 
1135         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1136                 buildPerson());
1137         mDataManager.addOrUpdateConversationInfo(shortcut);
1138 
1139         ConversationStatus cs1 = new ConversationStatus.Builder("cs1", 9)
1140                 .setEndTimeMillis(System.currentTimeMillis())
1141                 .build();
1142         ConversationStatus cs2 = new ConversationStatus.Builder("cs2", 10)
1143                 .build();
1144         ConversationStatus cs3 = new ConversationStatus.Builder("cs3", 1)
1145                 .setEndTimeMillis(Long.MAX_VALUE)
1146                 .build();
1147         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs1);
1148         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2);
1149         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs3);
1150         mLooper.dispatchAll();
1151 
1152         PeopleService.ConversationsListener listener = mock(
1153                 PeopleService.ConversationsListener.class);
1154         mDataManager.addConversationsListener(listener);
1155         mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
1156         mLooper.dispatchAll();
1157 
1158         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1159                 .doesNotContain(cs1);
1160         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1161                 .contains(cs2);
1162         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1163                 .contains(cs3);
1164         ArgumentCaptor<List<ConversationChannel>> capturedConversation = ArgumentCaptor.forClass(
1165                 List.class);
1166         verify(listener, times(1)).onConversationsUpdate(capturedConversation.capture());
1167         List<ConversationChannel> results = capturedConversation.getValue();
1168         ConversationChannel result = Iterables.getOnlyElement(capturedConversation.getValue());
1169         // CHeck cs1 has been removed and only cs2 and cs3 remain.
1170         assertThat(result.getStatuses()).containsExactly(cs2, cs3);
1171     }
1172 
1173     @Test
testDoNotUncacheShortcutWithActiveNotifications()1174     public void testDoNotUncacheShortcutWithActiveNotifications() {
1175         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1176         NotificationListenerService listenerService =
1177                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1178 
1179         for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
1180             String shortcutId = TEST_SHORTCUT_ID + i;
1181             ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
1182                     buildPerson());
1183             shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1184             mDataManager.addOrUpdateConversationInfo(shortcut);
1185             when(mNotification.getShortcutId()).thenReturn(shortcutId);
1186             sendGenericNotification();
1187         }
1188 
1189         mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal);
1190 
1191         verify(mShortcutServiceInternal, never()).uncacheShortcuts(
1192                 anyInt(), anyString(), anyString(), anyList(), anyInt(), anyInt());
1193     }
1194 
1195     @Test
testUncacheOldestCachedShortcut()1196     public void testUncacheOldestCachedShortcut() {
1197         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1198         NotificationListenerService listenerService =
1199                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1200 
1201         for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
1202             String shortcutId = TEST_SHORTCUT_ID + i;
1203             ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
1204                     buildPerson());
1205             shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1206             mDataManager.addOrUpdateConversationInfo(shortcut);
1207             when(mNotification.getShortcutId()).thenReturn(shortcutId);
1208             when(mGenericSbn.getPostTime()).thenReturn(100L + i);
1209             sendGenericNotification();
1210             listenerService.onNotificationRemoved(mGenericSbn, null,
1211                     NotificationListenerService.REASON_CANCEL);
1212         }
1213 
1214         // Only the shortcut #0 is uncached, all the others are not.
1215         verify(mShortcutServiceInternal).uncacheShortcuts(
1216                 anyInt(), any(), eq(TEST_PKG_NAME),
1217                 eq(Collections.singletonList(TEST_SHORTCUT_ID + 0)), eq(USER_ID_PRIMARY),
1218                 eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1219         for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
1220             verify(mShortcutServiceInternal, never()).uncacheShortcuts(
1221                     anyInt(), anyString(), anyString(),
1222                     eq(Collections.singletonList(TEST_SHORTCUT_ID + i)), anyInt(),
1223                     eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1224         }
1225     }
1226 
1227     @Test
testUncacheOldestCachedShortcut_missingNotificationEvents()1228     public void testUncacheOldestCachedShortcut_missingNotificationEvents() {
1229         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1230 
1231         for (int i = 0; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
1232             String shortcutId = TEST_SHORTCUT_ID + i;
1233             ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
1234                     buildPerson());
1235             shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1236             mShortcutChangeCallback.onShortcutsAddedOrUpdated(
1237                     TEST_PKG_NAME,
1238                     Collections.singletonList(shortcut),
1239                     UserHandle.of(USER_ID_PRIMARY));
1240             mLooper.dispatchAll();
1241         }
1242 
1243         // Only the shortcut #0 is uncached, all the others are not.
1244         verify(mShortcutServiceInternal).uncacheShortcuts(
1245                 anyInt(), any(), eq(TEST_PKG_NAME),
1246                 eq(Collections.singletonList(TEST_SHORTCUT_ID + 0)), eq(USER_ID_PRIMARY),
1247                 eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1248         for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
1249             verify(mShortcutServiceInternal, never()).uncacheShortcuts(
1250                     anyInt(), anyString(), anyString(),
1251                     eq(Collections.singletonList(TEST_SHORTCUT_ID + i)), anyInt(),
1252                     eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1253         }
1254     }
1255 
1256     @Test
testUncacheOldestCachedShortcut_legacyConversation()1257     public void testUncacheOldestCachedShortcut_legacyConversation() {
1258         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1259 
1260         // Add an extra conversation with a legacy type (no creationTime)
1261         ConversationStore conversationStore = mDataManager
1262                 .getUserDataForTesting(USER_ID_PRIMARY)
1263                 .getOrCreatePackageData(TEST_PKG_NAME)
1264                 .getConversationStore();
1265         ConversationInfo.Builder builder = new ConversationInfo.Builder();
1266         builder.setShortcutId(TEST_SHORTCUT_ID + 0);
1267         builder.setShortcutFlags(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1268         mDataManager.updateConversationStoreThenNotifyListeners(
1269                 conversationStore,
1270                 builder.build(),
1271                 TEST_PKG_NAME, USER_ID_PRIMARY);
1272         for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
1273             String shortcutId = TEST_SHORTCUT_ID + i;
1274             ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, shortcutId,
1275                     buildPerson());
1276             shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1277             mShortcutChangeCallback.onShortcutsAddedOrUpdated(
1278                     TEST_PKG_NAME,
1279                     Collections.singletonList(shortcut),
1280                     UserHandle.of(USER_ID_PRIMARY));
1281             mLooper.dispatchAll();
1282         }
1283 
1284         // Only the shortcut #0 is uncached, all the others are not.
1285         verify(mShortcutServiceInternal).uncacheShortcuts(
1286                 anyInt(), any(), eq(TEST_PKG_NAME),
1287                 eq(Collections.singletonList(TEST_SHORTCUT_ID + 0)), eq(USER_ID_PRIMARY),
1288                 eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1289         for (int i = 1; i < DataManager.MAX_CACHED_RECENT_SHORTCUTS + 1; i++) {
1290             verify(mShortcutServiceInternal, never()).uncacheShortcuts(
1291                     anyInt(), anyString(), anyString(),
1292                     eq(Collections.singletonList(TEST_SHORTCUT_ID + i)), anyInt(),
1293                     eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1294         }
1295     }
1296 
1297     @Test
testBackupAndRestoration()1298     public void testBackupAndRestoration()
1299             throws IntentFilter.MalformedMimeTypeException {
1300         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1301         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1302                 null);
1303         AppTarget appTarget = new AppTarget.Builder(new AppTargetId(TEST_SHORTCUT_ID), shortcut)
1304                 .build();
1305         AppTargetEvent appTargetEvent =
1306                 new AppTargetEvent.Builder(appTarget, AppTargetEvent.ACTION_LAUNCH)
1307                         .setLaunchLocation(ChooserActivity.LAUNCH_LOCATION_DIRECT_SHARE)
1308                         .build();
1309         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SEND, "image/jpg");
1310 
1311         mDataManager.reportShareTargetEvent(appTargetEvent, intentFilter);
1312         byte[] payload = mDataManager.getBackupPayload(USER_ID_PRIMARY);
1313 
1314         DataManager dataManager = new DataManager(mContext, mInjector, mLooper.getLooper());
1315         dataManager.onUserUnlocked(USER_ID_PRIMARY);
1316         dataManager.restore(USER_ID_PRIMARY, payload);
1317         ConversationInfo conversationInfo = dataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
1318                 .getConversationStore()
1319                 .getConversation(TEST_SHORTCUT_ID);
1320         assertNotNull(conversationInfo);
1321         assertEquals(conversationInfo.getShortcutId(), TEST_SHORTCUT_ID);
1322     }
1323 
1324     @Test
testGetRecentConversations()1325     public void testGetRecentConversations() {
1326         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1327 
1328         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1329                 buildPerson());
1330         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1331         mDataManager.addOrUpdateConversationInfo(shortcut);
1332 
1333         sendGenericNotification();
1334 
1335         List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
1336         assertEquals(1, result.size());
1337         assertEquals(shortcut.getId(), result.get(0).getShortcutInfo().getId());
1338         assertEquals(1, result.get(0).getShortcutInfo().getPersons().length);
1339         assertEquals(CONTACT_URI, result.get(0).getShortcutInfo().getPersons()[0].getUri());
1340         assertEquals(mParentNotificationChannel.getId(),
1341                 result.get(0).getNotificationChannel().getId());
1342         assertEquals(null, result.get(0).getNotificationChannel().getParentChannelId());
1343         assertEquals(mGenericSbn.getPostTime(), result.get(0).getLastEventTimestamp());
1344         assertTrue(result.get(0).hasActiveNotifications());
1345     }
1346 
1347     @Test
testGetRecentConversationsGetsPersonsData()1348     public void testGetRecentConversationsGetsPersonsData() {
1349         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1350 
1351         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1352                 buildPerson());
1353         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1354         mDataManager.addOrUpdateConversationInfo(shortcut);
1355 
1356         sendGenericNotification();
1357 
1358         mDataManager.getRecentConversations(USER_ID_PRIMARY);
1359 
1360         verify(mShortcutServiceInternal).getShortcuts(
1361                 anyInt(), anyString(), anyLong(), anyString(), anyList(), any(), any(),
1362                 mQueryFlagsCaptor.capture(), anyInt(), anyInt(), anyInt());
1363         Integer queryFlags = mQueryFlagsCaptor.getValue();
1364         assertThat(hasFlag(queryFlags, ShortcutQuery.FLAG_GET_PERSONS_DATA)).isTrue();
1365     }
1366 
1367     @Test
testPruneOldRecentConversations()1368     public void testPruneOldRecentConversations() {
1369         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1370 
1371         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1372                 buildPerson());
1373         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1374         mDataManager.addOrUpdateConversationInfo(shortcut);
1375 
1376         NotificationListenerService listenerService =
1377                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1378         when(mNotification.getShortcutId()).thenReturn(TEST_SHORTCUT_ID);
1379         sendGenericNotification();
1380         listenerService.onNotificationRemoved(mGenericSbn, null,
1381                 NotificationListenerService.REASON_CLICK);
1382 
1383         mDataManager.pruneOldRecentConversations(USER_ID_PRIMARY,
1384                 System.currentTimeMillis() + (10 * DateUtils.DAY_IN_MILLIS) + 1);
1385 
1386         verify(mShortcutServiceInternal).uncacheShortcuts(
1387                 anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList(TEST_SHORTCUT_ID)),
1388                 eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1389     }
1390 
1391     @Test
testGetLastInteraction()1392     public void testGetLastInteraction() {
1393         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1394 
1395         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1396                 buildPerson());
1397         mDataManager.addOrUpdateConversationInfo(shortcut);
1398 
1399         sendGenericNotification();
1400 
1401         assertEquals(mGenericSbn.getPostTime(),
1402                 mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID));
1403         assertEquals(0L,
1404                 mDataManager.getLastInteraction("not_test_pkg", USER_ID_PRIMARY, TEST_SHORTCUT_ID));
1405         assertEquals(0L,
1406                 mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_PRIMARY_MANAGED,
1407                         TEST_SHORTCUT_ID));
1408         assertEquals(0L,
1409                 mDataManager.getLastInteraction(TEST_PKG_NAME, USER_ID_SECONDARY,
1410                         TEST_SHORTCUT_ID));
1411     }
1412 
1413     @Test
testAddOrUpdateStatus_noCachedShortcut()1414     public void testAddOrUpdateStatus_noCachedShortcut() {
1415         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1416 
1417         ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
1418 
1419         try {
1420             mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
1421             fail("Updated a conversation info that didn't previously exist");
1422         } catch (IllegalArgumentException e) {
1423             // good
1424         }
1425     }
1426 
1427     @Test
testAddOrUpdateStatus()1428     public void testAddOrUpdateStatus() {
1429         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1430 
1431         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1432                 buildPerson());
1433         mDataManager.addOrUpdateConversationInfo(shortcut);
1434 
1435         ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
1436         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
1437 
1438         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1439                 .contains(cs);
1440 
1441         ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
1442         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2);
1443 
1444         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1445                 .contains(cs);
1446         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1447                 .contains(cs2);
1448 
1449         verify(mAlarmManager, never()).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
1450     }
1451 
1452     @Test
testAddOrUpdateStatus_schedulesJob()1453     public void testAddOrUpdateStatus_schedulesJob() {
1454         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1455 
1456         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1457                 buildPerson());
1458         mDataManager.addOrUpdateConversationInfo(shortcut);
1459 
1460         ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY)
1461                 .setEndTimeMillis(1000)
1462                 .build();
1463         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
1464 
1465         ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME)
1466                 .setEndTimeMillis(3000)
1467                 .build();
1468         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2);
1469 
1470         verify(mAlarmManager, times(2)).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
1471     }
1472 
1473     @Test
testClearStatus()1474     public void testClearStatus() {
1475         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1476 
1477         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1478                 buildPerson());
1479         mDataManager.addOrUpdateConversationInfo(shortcut);
1480 
1481         ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
1482         ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
1483         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
1484         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2);
1485         mLooper.dispatchAll();
1486 
1487         PeopleService.ConversationsListener listener = mock(
1488                 PeopleService.ConversationsListener.class);
1489         mDataManager.addConversationsListener(listener);
1490         mDataManager.clearStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2.getId());
1491         mLooper.dispatchAll();
1492 
1493         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1494                 .contains(cs);
1495         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1496                 .doesNotContain(cs2);
1497         ArgumentCaptor<List<ConversationChannel>> capturedConversation = ArgumentCaptor.forClass(
1498                 List.class);
1499         verify(listener, times(1)).onConversationsUpdate(capturedConversation.capture());
1500         ConversationChannel result = Iterables.getOnlyElement(capturedConversation.getValue());
1501         assertThat(result.getStatuses()).containsExactly(cs);
1502     }
1503 
1504     @Test
testClearStatuses()1505     public void testClearStatuses() {
1506         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1507 
1508         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1509                 buildPerson());
1510         mDataManager.addOrUpdateConversationInfo(shortcut);
1511 
1512         ConversationStatus cs = new ConversationStatus.Builder("id", ACTIVITY_ANNIVERSARY).build();
1513         ConversationStatus cs2 = new ConversationStatus.Builder("id2", ACTIVITY_GAME).build();
1514         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs);
1515         mDataManager.addOrUpdateStatus(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, cs2);
1516         mLooper.dispatchAll();
1517 
1518         PeopleService.ConversationsListener listener = mock(
1519                 PeopleService.ConversationsListener.class);
1520         mDataManager.addConversationsListener(listener);
1521         mDataManager.clearStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID);
1522         mLooper.dispatchAll();
1523 
1524         assertThat(mDataManager.getStatuses(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID))
1525                 .isEmpty();
1526         ArgumentCaptor<List<ConversationChannel>> capturedConversation = ArgumentCaptor.forClass(
1527                 List.class);
1528         verify(listener, times(1)).onConversationsUpdate(capturedConversation.capture());
1529         ConversationChannel result = Iterables.getOnlyElement(capturedConversation.getValue());
1530         assertThat(result.getStatuses()).isEmpty();
1531     }
1532 
1533     @Test
testNonCachedShortcutNotInRecentList()1534     public void testNonCachedShortcutNotInRecentList() {
1535         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1536 
1537         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY_MANAGED,
1538                 TEST_SHORTCUT_ID, buildPerson());
1539         mDataManager.addOrUpdateConversationInfo(shortcut);
1540 
1541         sendGenericNotification();
1542 
1543         List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
1544         assertTrue(result.isEmpty());
1545     }
1546 
1547     @Test
testCustomizedConversationNotInRecentList()1548     public void testCustomizedConversationNotInRecentList() {
1549         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1550 
1551         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1552                 buildPerson());
1553         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1554         mDataManager.addOrUpdateConversationInfo(shortcut);
1555 
1556         // Post a notification and customize the notification settings.
1557         NotificationListenerService listenerService =
1558                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1559         sendGenericNotification();
1560         listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY),
1561                 mNotificationChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1562 
1563         List<ConversationChannel> result = mDataManager.getRecentConversations(USER_ID_PRIMARY);
1564         assertTrue(result.isEmpty());
1565     }
1566 
1567     @Test
testNotificationRemoved()1568     public void testNotificationRemoved() {
1569         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1570 
1571         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1572                 buildPerson());
1573         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1574         mDataManager.addOrUpdateConversationInfo(shortcut);
1575 
1576         NotificationListenerService listenerService =
1577                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1578         sendGenericNotification();
1579         // posting updates the last interaction time, so delay before deletion
1580         try {
1581             Thread.sleep(500);
1582         } catch (InterruptedException e) {
1583             e.printStackTrace();
1584         }
1585         long approxDeletionTime = System.currentTimeMillis();
1586         listenerService.onNotificationRemoved(mGenericSbn, null,
1587                 NotificationListenerService.REASON_CANCEL);
1588 
1589         ConversationInfo conversationInfo = mDataManager.getPackage(TEST_PKG_NAME, USER_ID_PRIMARY)
1590                 .getConversationStore()
1591                 .getConversation(TEST_SHORTCUT_ID);
1592         assertTrue(conversationInfo.getLastEventTimestamp() - approxDeletionTime < 100);
1593     }
1594 
1595     @Test
1596     public void testRemoveRecentConversation() {
1597         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1598 
1599         ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1600                 buildPerson());
1601         shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1602         mDataManager.addOrUpdateConversationInfo(shortcut);
1603 
1604         NotificationListenerService listenerService =
1605                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1606         sendGenericNotification();
1607         listenerService.onNotificationRemoved(mGenericSbn, null,
1608                 NotificationListenerService.REASON_CANCEL);
1609         mDataManager.removeRecentConversation(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID,
1610                 USER_ID_PRIMARY);
1611 
1612         verify(mShortcutServiceInternal).uncacheShortcuts(
1613                 anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList(TEST_SHORTCUT_ID)),
1614                 eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1615     }
1616 
1617     @Test
1618     public void testRemoveAllRecentConversations() {
1619         mDataManager.onUserUnlocked(USER_ID_PRIMARY);
1620 
1621         ShortcutInfo shortcut1 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "1",
1622                 buildPerson());
1623         shortcut1.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1624         mDataManager.addOrUpdateConversationInfo(shortcut1);
1625 
1626         ShortcutInfo shortcut2 = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, "2",
1627                 buildPerson());
1628         shortcut2.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS);
1629         mDataManager.addOrUpdateConversationInfo(shortcut2);
1630 
1631         NotificationListenerService listenerService =
1632                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1633 
1634         // Post a notification and then dismiss it for conversation #1.
1635         when(mNotification.getShortcutId()).thenReturn("1");
1636         sendGenericNotification();
1637         listenerService.onNotificationRemoved(mGenericSbn, null,
1638                 NotificationListenerService.REASON_CANCEL);
1639 
1640         // Post a notification for conversation #2, but don't dismiss it. Its shortcut won't be
1641         // uncached when removeAllRecentConversations() is called.
1642         when(mNotification.getShortcutId()).thenReturn("2");
1643         sendGenericNotification();
1644 
1645         mDataManager.removeAllRecentConversations(USER_ID_PRIMARY);
1646 
1647         verify(mShortcutServiceInternal).uncacheShortcuts(
1648                 anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList("1")),
1649                 eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1650         verify(mShortcutServiceInternal, never()).uncacheShortcuts(
1651                 anyInt(), any(), eq(TEST_PKG_NAME), eq(Collections.singletonList("2")),
1652                 eq(USER_ID_PRIMARY), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS));
1653     }
1654 
1655     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
1656         LocalServices.removeServiceForTest(clazz);
1657         LocalServices.addService(clazz, mock);
1658     }
1659 
1660     private List<ConversationInfo> getConversationsInPrimary() {
1661         List<ConversationInfo> conversations = new ArrayList<>();
1662         mDataManager.forPackagesInProfile(USER_ID_PRIMARY,
1663                 packageData -> packageData.forAllConversations(conversations::add));
1664         return conversations;
1665     }
1666 
getActiveSlotsForTestShortcut(Set<Integer> eventTypes)1667     private List<Range<Long>> getActiveSlotsForTestShortcut(Set<Integer> eventTypes) {
1668         List<Range<Long>> activeSlots = new ArrayList<>();
1669         mDataManager.forPackagesInProfile(USER_ID_PRIMARY, packageData ->
1670                 activeSlots.addAll(
1671                         packageData.getEventHistory(TEST_SHORTCUT_ID)
1672                                 .getEventIndex(eventTypes)
1673                                 .getActiveTimeSlots()));
1674         return activeSlots;
1675     }
1676 
getActiveSlotsForAppShares()1677     private List<Range<Long>> getActiveSlotsForAppShares() {
1678         List<Range<Long>> activeSlots = new ArrayList<>();
1679         mDataManager.forPackagesInProfile(USER_ID_PRIMARY, packageData ->
1680                 activeSlots.addAll(
1681                         packageData.getClassLevelEventHistory(TEST_CLASS_NAME)
1682                                 .getEventIndex(Event.SHARE_EVENT_TYPES)
1683                                 .getActiveTimeSlots()));
1684         return activeSlots;
1685     }
1686 
buildShortcutInfo(String packageName, int userId, String id, @Nullable Person person)1687     private ShortcutInfo buildShortcutInfo(String packageName, int userId, String id,
1688             @Nullable Person person) {
1689         Context mockContext = mock(Context.class);
1690         when(mockContext.getPackageName()).thenReturn(packageName);
1691         when(mockContext.getUserId()).thenReturn(userId);
1692         when(mockContext.getUser()).thenReturn(UserHandle.of(userId));
1693         ShortcutInfo.Builder builder = new ShortcutInfo.Builder(mockContext, id)
1694                 .setShortLabel(id)
1695                 .setLongLived(true)
1696                 .setIntent(new Intent("TestIntent"));
1697         if (person != null) {
1698             builder.setPersons(new Person[]{person});
1699         }
1700         return builder.build();
1701     }
1702 
buildPerson()1703     private Person buildPerson() {
1704         return buildPerson(true, false);
1705     }
1706 
buildPerson(boolean isImportant, boolean isBot)1707     private Person buildPerson(boolean isImportant, boolean isBot) {
1708         return new Person.Builder()
1709                 .setImportant(isImportant)
1710                 .setBot(isBot)
1711                 .setUri(CONTACT_URI)
1712                 .build();
1713     }
1714 
buildUserInfo(int userId)1715     private UserInfo buildUserInfo(int userId) {
1716         return new UserInfo(userId, "", 0);
1717     }
1718 
1719     /**
1720      * Returns {@code true} iff {@link ShortcutQuery}'s {@code queryFlags} has {@code flag} set.
1721      */
hasFlag(int queryFlags, int flag)1722     private static boolean hasFlag(int queryFlags, int flag) {
1723         return (queryFlags & flag) != 0;
1724     }
1725 
1726     // "Sends" a notification to a non-customized notification channel - the notification channel
1727     // is something generic like "messages" and the notification has a  shortcut id
sendGenericNotification()1728     private void sendGenericNotification() {
1729         sendGenericNotificationWithKey(GENERIC_KEY);
1730     }
1731 
1732     // "Sends" a notification to a non-customized notification channel with the specified key.
sendGenericNotificationWithKey(String key)1733     private void sendGenericNotificationWithKey(String key) {
1734         when(mGenericSbn.getKey()).thenReturn(key);
1735         when(mNotification.getChannelId()).thenReturn(PARENT_NOTIFICATION_CHANNEL_ID);
1736         doAnswer(invocationOnMock -> {
1737             NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
1738                     invocationOnMock.getArguments()[1];
1739             ranking.populate(
1740                     /* key= */ (String) invocationOnMock.getArguments()[0],
1741                     /* rank= */ 0,
1742                     /* matchesInterruptionFilter= */ false,
1743                     /* visibilityOverride= */ 0,
1744                     /* suppressedVisualEffects= */ 0,
1745                     mParentNotificationChannel.getImportance(),
1746                     /* explanation= */ null,
1747                     /* overrideGroupKey= */ null,
1748                     mParentNotificationChannel,
1749                     /* overridePeople= */ null,
1750                     /* snoozeCriteria= */ null,
1751                     /* showBadge= */ true,
1752                     /* userSentiment= */ 0,
1753                     /* hidden= */ false,
1754                     /* lastAudiblyAlertedMs= */ -1,
1755                     /* noisy= */ false,
1756                     /* smartActions= */ null,
1757                     /* smartReplies= */ null,
1758                     /* canBubble= */ false,
1759                     /* isTextChanged= */ false,
1760                     /* isConversation= */ false,
1761                     /* shortcutInfo= */ null,
1762                     /* rankingAdjustment= */ 0,
1763                     /* isBubble= */ false,
1764                     /* proposedImportance= */ 0,
1765                     /* sensitiveContent= */ false
1766             );
1767             return true;
1768         }).when(mRankingMap).getRanking(eq(key),
1769                 any(NotificationListenerService.Ranking.class));
1770         NotificationListenerService listenerService =
1771                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1772         listenerService.onNotificationPosted(mGenericSbn, mRankingMap);
1773     }
1774 
1775     // "Sends" a notification to a customized notification channel - the notification channel
1776     // is specific to a person, and the channel has a convo id matching the notification's shortcut
1777     // and the channel has a parent channel id
sendConvoNotification()1778     private void sendConvoNotification() {
1779         when(mNotification.getChannelId()).thenReturn(NOTIFICATION_CHANNEL_ID);
1780         doAnswer(invocationOnMock -> {
1781             NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
1782                     invocationOnMock.getArguments()[1];
1783             ranking.populate(
1784                     /* key= */ (String) invocationOnMock.getArguments()[0],
1785                     /* rank= */ 0,
1786                     /* matchesInterruptionFilter= */ false,
1787                     /* visibilityOverride= */ 0,
1788                     /* suppressedVisualEffects= */ 0,
1789                     mParentNotificationChannel.getImportance(),
1790                     /* explanation= */ null,
1791                     /* overrideGroupKey= */ null,
1792                     mParentNotificationChannel,
1793                     /* overridePeople= */ null,
1794                     /* snoozeCriteria= */ null,
1795                     /* showBadge= */ true,
1796                     /* userSentiment= */ 0,
1797                     /* hidden= */ false,
1798                     /* lastAudiblyAlertedMs= */ -1,
1799                     /* noisy= */ false,
1800                     /* smartActions= */ null,
1801                     /* smartReplies= */ null,
1802                     /* canBubble= */ false,
1803                     /* isTextChanged= */ false,
1804                     /* isConversation= */ false,
1805                     /* shortcutInfo= */ null,
1806                     /* rankingAdjustment= */ 0,
1807                     /* isBubble= */ false,
1808                     /* proposedImportance= */ 0,
1809                     /* sensitiveContent= */ false
1810             );
1811             return true;
1812         }).when(mRankingMap).getRanking(eq(CUSTOM_KEY),
1813                 any(NotificationListenerService.Ranking.class));
1814 
1815         NotificationListenerService listenerService =
1816                 mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY);
1817         listenerService.onNotificationPosted(mConvoSbn, mRankingMap);
1818     }
1819 
1820     private class TestContactsQueryHelper extends ContactsQueryHelper {
1821 
1822         private Uri mContactUri;
1823         private boolean mIsStarred;
1824         private String mPhoneNumber;
1825 
TestContactsQueryHelper(Context context)1826         TestContactsQueryHelper(Context context) {
1827             super(context);
1828             mContactUri = Uri.parse(CONTACT_URI);
1829             mIsStarred = false;
1830             mPhoneNumber = PHONE_NUMBER;
1831         }
1832 
1833         @Override
query(@onNull String contactUri)1834         boolean query(@NonNull String contactUri) {
1835             return true;
1836         }
1837 
1838         @Override
querySince(long sinceTime)1839         boolean querySince(long sinceTime) {
1840             return true;
1841         }
1842 
1843         @Override
1844         @Nullable
getContactUri()1845         Uri getContactUri() {
1846             return mContactUri;
1847         }
1848 
1849         @Override
isStarred()1850         boolean isStarred() {
1851             return mIsStarred;
1852         }
1853 
1854         @Override
1855         @Nullable
getPhoneNumber()1856         String getPhoneNumber() {
1857             return mPhoneNumber;
1858         }
1859     }
1860 
1861     private class TestCallLogQueryHelper extends CallLogQueryHelper {
1862 
1863         private final BiConsumer<String, Event> mEventConsumer;
1864 
TestCallLogQueryHelper(Context context, BiConsumer<String, Event> eventConsumer)1865         TestCallLogQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) {
1866             super(context, eventConsumer);
1867             mEventConsumer = eventConsumer;
1868         }
1869 
1870         @Override
querySince(long sinceTime)1871         boolean querySince(long sinceTime) {
1872             return true;
1873         }
1874 
1875         @Override
getLastCallTimestamp()1876         long getLastCallTimestamp() {
1877             return 100L;
1878         }
1879     }
1880 
1881     private class TestSmsQueryHelper extends SmsQueryHelper {
1882 
1883         private final BiConsumer<String, Event> mEventConsumer;
1884 
TestSmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer)1885         TestSmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) {
1886             super(context, eventConsumer);
1887             mEventConsumer = eventConsumer;
1888         }
1889 
1890         @Override
querySince(long sinceTime)1891         boolean querySince(long sinceTime) {
1892             return true;
1893         }
1894 
1895         @Override
getLastMessageTimestamp()1896         long getLastMessageTimestamp() {
1897             return 100L;
1898         }
1899     }
1900 
1901     private class TestMmsQueryHelper extends MmsQueryHelper {
1902 
1903         private final BiConsumer<String, Event> mEventConsumer;
1904 
TestMmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer)1905         TestMmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer) {
1906             super(context, eventConsumer);
1907             mEventConsumer = eventConsumer;
1908         }
1909 
1910         @Override
querySince(long sinceTime)1911         boolean querySince(long sinceTime) {
1912             return true;
1913         }
1914 
1915         @Override
getLastMessageTimestamp()1916         long getLastMessageTimestamp() {
1917             return 100L;
1918         }
1919     }
1920 
1921     private class TestUsageStatsQueryHelper extends UsageStatsQueryHelper {
1922 
1923         private final EventListener mEventListener;
1924 
TestUsageStatsQueryHelper(int userId, Function<String, PackageData> packageDataGetter, EventListener eventListener)1925         TestUsageStatsQueryHelper(int userId,
1926                 Function<String, PackageData> packageDataGetter,
1927                 EventListener eventListener) {
1928             super(userId, packageDataGetter, eventListener);
1929             mEventListener = eventListener;
1930         }
1931     }
1932 
1933     private class TestInjector extends DataManager.Injector {
1934 
1935         private final TestContactsQueryHelper mContactsQueryHelper =
1936                 new TestContactsQueryHelper(mContext);
1937         private TestCallLogQueryHelper mCallLogQueryHelper;
1938         private TestMmsQueryHelper mMmsQueryHelper;
1939         private TestSmsQueryHelper mSmsQueryHelper;
1940         private TestUsageStatsQueryHelper mUsageStatsQueryHelper;
1941 
1942         @Override
createScheduledExecutor()1943         ScheduledExecutorService createScheduledExecutor() {
1944             return mExecutorService;
1945         }
1946 
1947         @Override
getBackgroundExecutor()1948         Executor getBackgroundExecutor() {
1949             return Runnable::run;
1950         }
1951 
1952         @Override
createContactsQueryHelper(Context context)1953         ContactsQueryHelper createContactsQueryHelper(Context context) {
1954             return mContactsQueryHelper;
1955         }
1956 
1957         @Override
createCallLogQueryHelper(Context context, BiConsumer<String, Event> eventConsumer)1958         CallLogQueryHelper createCallLogQueryHelper(Context context,
1959                 BiConsumer<String, Event> eventConsumer) {
1960             mCallLogQueryHelper = new TestCallLogQueryHelper(context, eventConsumer);
1961             return mCallLogQueryHelper;
1962         }
1963 
1964         @Override
createMmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer)1965         MmsQueryHelper createMmsQueryHelper(Context context,
1966                 BiConsumer<String, Event> eventConsumer) {
1967             mMmsQueryHelper = new TestMmsQueryHelper(context, eventConsumer);
1968             return mMmsQueryHelper;
1969         }
1970 
1971         @Override
createSmsQueryHelper(Context context, BiConsumer<String, Event> eventConsumer)1972         SmsQueryHelper createSmsQueryHelper(Context context,
1973                 BiConsumer<String, Event> eventConsumer) {
1974             mSmsQueryHelper = new TestSmsQueryHelper(context, eventConsumer);
1975             return mSmsQueryHelper;
1976         }
1977 
1978         @Override
createUsageStatsQueryHelper(@serIdInt int userId, Function<String, PackageData> packageDataGetter, UsageStatsQueryHelper.EventListener eventListener)1979         UsageStatsQueryHelper createUsageStatsQueryHelper(@UserIdInt int userId,
1980                 Function<String, PackageData> packageDataGetter,
1981                 UsageStatsQueryHelper.EventListener eventListener) {
1982             mUsageStatsQueryHelper =
1983                     new TestUsageStatsQueryHelper(userId, packageDataGetter, eventListener);
1984             return mUsageStatsQueryHelper;
1985         }
1986     }
1987 }
1988