diff options
11 files changed, 909 insertions, 589 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java b/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java new file mode 100644 index 000000000000..68a829ca2e38 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/people/NotificationHelper.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.people; + +import static android.Manifest.permission.READ_CONTACTS; +import static android.app.Notification.CATEGORY_MISSED_CALL; +import static android.app.Notification.EXTRA_MESSAGES; +import static android.app.Notification.EXTRA_PEOPLE_LIST; + +import android.annotation.Nullable; +import android.app.Notification; +import android.app.Person; +import android.content.pm.PackageManager; +import android.os.Parcelable; +import android.service.notification.StatusBarNotification; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** Helper functions to handle notifications in People Tiles. */ +public class NotificationHelper { + private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; + private static final String TAG = "PeopleNotificationHelper"; + + /** Returns the notification with highest priority to be shown in People Tiles. */ + public static NotificationEntry getHighestPriorityNotification( + Set<NotificationEntry> notificationEntries) { + if (notificationEntries == null || notificationEntries.isEmpty()) { + return null; + } + + return notificationEntries + .stream() + .filter(NotificationHelper::isMissedCallOrHasContent) + .sorted(notificationEntryComparator) + .findFirst().orElse(null); + } + + + /** Notification comparator, checking category and timestamps, in reverse order of priority. */ + public static Comparator<NotificationEntry> notificationEntryComparator = + new Comparator<NotificationEntry>() { + @Override + public int compare(NotificationEntry e1, NotificationEntry e2) { + Notification n1 = e1.getSbn().getNotification(); + Notification n2 = e2.getSbn().getNotification(); + + boolean missedCall1 = isMissedCall(n1); + boolean missedCall2 = isMissedCall(n2); + if (missedCall1 && !missedCall2) { + return -1; + } + if (!missedCall1 && missedCall2) { + return 1; + } + + // Get messages in reverse chronological order. + List<Notification.MessagingStyle.Message> messages1 = + getMessagingStyleMessages(n1); + List<Notification.MessagingStyle.Message> messages2 = + getMessagingStyleMessages(n2); + + if (messages1 != null && messages2 != null) { + Notification.MessagingStyle.Message message1 = messages1.get(0); + Notification.MessagingStyle.Message message2 = messages2.get(0); + return (int) (message2.getTimestamp() - message1.getTimestamp()); + } + + if (messages1 == null) { + return 1; + } + if (messages2 == null) { + return -1; + } + return (int) (n2.when - n1.when); + } + }; + + /** Returns whether {@code e} is a missed call notification. */ + public static boolean isMissedCall(NotificationEntry e) { + return e != null && e.getSbn().getNotification() != null + && isMissedCall(e.getSbn().getNotification()); + } + + /** Returns whether {@code notification} is a missed call notification. */ + public static boolean isMissedCall(Notification notification) { + return notification != null && Objects.equals(notification.category, CATEGORY_MISSED_CALL); + } + + private static boolean hasContent(NotificationEntry e) { + if (e == null) { + return false; + } + List<Notification.MessagingStyle.Message> messages = + getMessagingStyleMessages(e.getSbn().getNotification()); + return messages != null && !messages.isEmpty(); + } + + /** Returns whether {@code e} is a valid conversation notification. */ + public static boolean isValid(NotificationEntry e) { + return e != null && e.getRanking() != null + && e.getRanking().getConversationShortcutInfo() != null + && e.getSbn().getNotification() != null; + } + + /** Returns whether conversation notification should be shown in People Tile. */ + public static boolean isMissedCallOrHasContent(NotificationEntry e) { + return isMissedCall(e) || hasContent(e); + } + + /** Returns whether {@code sbn}'s package has permission to read contacts. */ + public static boolean hasReadContactsPermission( + PackageManager packageManager, StatusBarNotification sbn) { + return packageManager.checkPermission(READ_CONTACTS, + sbn.getPackageName()) == PackageManager.PERMISSION_GRANTED; + } + + /** + * Returns whether a notification should be matched to other Tiles by Uri. + * + * <p>Currently only matches missed calls. + */ + public static boolean shouldMatchNotificationByUri(StatusBarNotification sbn) { + Notification notification = sbn.getNotification(); + if (notification == null) { + if (DEBUG) Log.d(TAG, "Notification is null"); + return false; + } + boolean isMissedCall = isMissedCall(notification); + if (!isMissedCall) { + if (DEBUG) Log.d(TAG, "Not missed call"); + } + return isMissedCall; + } + + /** + * Try to retrieve a valid Uri via {@code sbn}, falling back to the {@code + * contactUriFromShortcut} if valid. + */ + @Nullable + public static String getContactUri(StatusBarNotification sbn) { + // First, try to get a Uri from the Person directly set on the Notification. + ArrayList<Person> people = sbn.getNotification().extras.getParcelableArrayList( + EXTRA_PEOPLE_LIST); + if (people != null && people.get(0) != null) { + String contactUri = people.get(0).getUri(); + if (contactUri != null && !contactUri.isEmpty()) { + return contactUri; + } + } + + // Then, try to get a Uri from the Person set on the Notification message. + List<Notification.MessagingStyle.Message> messages = + getMessagingStyleMessages(sbn.getNotification()); + if (messages != null && !messages.isEmpty()) { + Notification.MessagingStyle.Message message = messages.get(0); + Person sender = message.getSenderPerson(); + if (sender != null && sender.getUri() != null && !sender.getUri().isEmpty()) { + return sender.getUri(); + } + } + + return null; + } + + /** + * Returns {@link Notification.MessagingStyle.Message}s from the Notification in chronological + * order from most recent to least. + */ + @VisibleForTesting + @Nullable + public static List<Notification.MessagingStyle.Message> getMessagingStyleMessages( + Notification notification) { + if (notification == null) { + return null; + } + if (Notification.MessagingStyle.class.equals(notification.getNotificationStyle()) + && notification.extras != null) { + final Parcelable[] messages = notification.extras.getParcelableArray(EXTRA_MESSAGES); + if (!ArrayUtils.isEmpty(messages)) { + List<Notification.MessagingStyle.Message> sortedMessages = + Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages); + sortedMessages.sort(Collections.reverseOrder( + Comparator.comparing(Notification.MessagingStyle.Message::getTimestamp))); + return sortedMessages; + } + } + return null; + } +} + diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java index 41957bc91561..a9640566d531 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleProvider.java @@ -16,36 +16,28 @@ package com.android.systemui.people; -import android.app.people.IPeopleManager; import android.content.ContentProvider; import android.content.ContentValues; -import android.content.Context; -import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Binder; import android.os.Bundle; -import android.os.ServiceManager; import android.os.UserHandle; import android.util.Log; import android.widget.RemoteViews; -import com.android.systemui.Dependency; +import com.android.systemui.people.widget.PeopleSpaceWidgetManager; import com.android.systemui.shared.system.PeopleProviderUtils; -import com.android.systemui.statusbar.notification.NotificationEntryManager; /** API that returns a People Tile preview. */ public class PeopleProvider extends ContentProvider { - - LauncherApps mLauncherApps; - IPeopleManager mPeopleManager; - NotificationEntryManager mNotificationEntryManager; - private static final String TAG = "PeopleProvider"; private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; private static final String EMPTY_STRING = ""; + PeopleSpaceWidgetManager mPeopleSpaceWidgetManager; + @Override public Bundle call(String method, String arg, Bundle extras) { if (!doesCallerHavePermission()) { @@ -83,17 +75,11 @@ public class PeopleProvider extends ContentProvider { throw new IllegalArgumentException("Null user handle"); } - // If services are not set as mocks in tests, fetch them now. - mPeopleManager = mPeopleManager != null ? mPeopleManager - : IPeopleManager.Stub.asInterface( - ServiceManager.getService(Context.PEOPLE_SERVICE)); - mLauncherApps = mLauncherApps != null ? mLauncherApps - : getContext().getSystemService(LauncherApps.class); - mNotificationEntryManager = mNotificationEntryManager != null ? mNotificationEntryManager - : Dependency.get(NotificationEntryManager.class); - - RemoteViews view = PeopleSpaceUtils.getPreview(getContext(), mPeopleManager, mLauncherApps, - mNotificationEntryManager, shortcutId, userHandle, packageName, extras); + if (mPeopleSpaceWidgetManager == null) { + mPeopleSpaceWidgetManager = new PeopleSpaceWidgetManager(getContext()); + } + RemoteViews view = + mPeopleSpaceWidgetManager.getPreview(shortcutId, userHandle, packageName, extras); if (view == null) { if (DEBUG) Log.d(TAG, "No preview available for shortcutId: " + shortcutId); return null; diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java index 38a6186ee7ea..ff14abe118ab 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java @@ -39,6 +39,7 @@ import android.widget.LinearLayout; import com.android.systemui.R; import com.android.systemui.people.widget.PeopleSpaceWidgetManager; +import com.android.systemui.people.widget.PeopleTileKey; import java.util.ArrayList; import java.util.List; @@ -136,14 +137,15 @@ public class PeopleSpaceActivity extends Activity { getSizeInDp(mContext, R.dimen.avatar_size_for_medium, mContext.getResources().getDisplayMetrics().density))); - tileView.setOnClickListener(v -> storeWidgetConfiguration(tile)); + PeopleTileKey key = new PeopleTileKey(tile); + tileView.setOnClickListener(v -> storeWidgetConfiguration(tile, key)); } catch (Exception e) { Log.e(TAG, "Couldn't retrieve shortcut information", e); } } /** Stores the user selected configuration for {@code mAppWidgetId}. */ - private void storeWidgetConfiguration(PeopleSpaceTile tile) { + private void storeWidgetConfiguration(PeopleSpaceTile tile, PeopleTileKey key) { if (PeopleSpaceUtils.DEBUG) { if (DEBUG) { Log.d(TAG, "Put " + tile.getUserName() + "'s shortcut ID: " @@ -151,7 +153,7 @@ public class PeopleSpaceActivity extends Activity { + mAppWidgetId); } } - mPeopleSpaceWidgetManager.addNewWidget(mAppWidgetId, tile); + mPeopleSpaceWidgetManager.addNewWidget(mAppWidgetId, key); finishActivity(); } diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index c0a16e11df68..eefe5ca93793 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -16,8 +16,11 @@ package com.android.systemui.people; -import static android.app.Notification.CATEGORY_MISSED_CALL; -import static android.app.Notification.EXTRA_MESSAGES; +import static com.android.systemui.people.NotificationHelper.getContactUri; +import static com.android.systemui.people.NotificationHelper.getMessagingStyleMessages; +import static com.android.systemui.people.NotificationHelper.hasReadContactsPermission; +import static com.android.systemui.people.NotificationHelper.isMissedCall; +import static com.android.systemui.people.NotificationHelper.shouldMatchNotificationByUri; import android.app.Notification; import android.app.people.ConversationChannel; @@ -27,6 +30,7 @@ import android.appwidget.AppWidgetManager; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.LauncherApps; +import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.database.Cursor; import android.database.SQLException; @@ -36,9 +40,6 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; -import android.os.Parcelable; -import android.os.ServiceManager; -import android.os.UserHandle; import android.os.UserManager; import android.provider.ContactsContract; import android.service.notification.StatusBarNotification; @@ -56,19 +57,16 @@ import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.R; import com.android.systemui.people.widget.AppWidgetOptionsHelper; import com.android.systemui.people.widget.PeopleTileKey; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -185,73 +183,85 @@ public class PeopleSpaceUtils { editor.putStringSet(storageKey, storedWidgetIds); } - /** Augments a single {@link PeopleSpaceTile} with notification content, if one is present. */ - public static PeopleSpaceTile augmentSingleTileFromVisibleNotifications(Context context, - PeopleSpaceTile tile, NotificationEntryManager notificationEntryManager) { - List<PeopleSpaceTile> augmentedTile = augmentTilesFromVisibleNotifications( - context, Arrays.asList(tile), notificationEntryManager); - return augmentedTile.get(0); + /** Returns notifications that match provided {@code contactUri}. */ + public static List<NotificationEntry> getNotificationsByUri( + PackageManager packageManager, String contactUri, + Map<PeopleTileKey, Set<NotificationEntry>> notifications) { + if (DEBUG) Log.d(TAG, "Getting notifications by contact URI."); + if (TextUtils.isEmpty(contactUri)) { + return new ArrayList<>(); + } + return notifications.entrySet().stream().flatMap(e -> e.getValue().stream()) + .filter(e -> + hasReadContactsPermission(packageManager, e.getSbn()) + && shouldMatchNotificationByUri(e.getSbn()) + && Objects.equals(contactUri, getContactUri(e.getSbn())) + ) + .collect(Collectors.toList()); } - /** Adds to {@code tiles} any visible notifications. */ - public static List<PeopleSpaceTile> augmentTilesFromVisibleNotifications(Context context, - List<PeopleSpaceTile> tiles, NotificationEntryManager notificationEntryManager) { - if (notificationEntryManager == null) { - Log.w(TAG, "NotificationEntryManager is null"); - return tiles; - } - Map<PeopleTileKey, NotificationEntry> visibleNotifications = notificationEntryManager - .getVisibleNotifications() - .stream() - .filter(entry -> entry.getRanking() != null - && entry.getRanking().getConversationShortcutInfo() != null) - .collect(Collectors.toMap(PeopleTileKey::new, e -> e, - // Handle duplicate keys to avoid crashes. - (e1, e2) -> e1.getSbn().getNotification().when - > e2.getSbn().getNotification().when ? e1 : e2)); + /** Returns the total messages in {@code notificationEntries}.*/ + public static int getMessagesCount(Set<NotificationEntry> notificationEntries) { if (DEBUG) { - Log.d(TAG, "Number of visible notifications:" + visibleNotifications.size()); + Log.d(TAG, "Calculating messages count from " + notificationEntries.size() + + " notifications."); } - return tiles - .stream() - .map(entry -> augmentTileFromVisibleNotifications( - context, entry, visibleNotifications)) - .collect(Collectors.toList()); + int messagesCount = 0; + for (NotificationEntry entry : notificationEntries) { + Notification notification = entry.getSbn().getNotification(); + // Should not count messages from missed call notifications. + if (isMissedCall(notification)) { + continue; + } + + List<Notification.MessagingStyle.Message> messages = + getMessagingStyleMessages(notification); + if (messages != null) { + messagesCount += messages.size(); + } + } + return messagesCount; } - static PeopleSpaceTile augmentTileFromVisibleNotifications(Context context, - PeopleSpaceTile tile, Map<PeopleTileKey, NotificationEntry> visibleNotifications) { - PeopleTileKey key = new PeopleTileKey( - tile.getId(), getUserId(tile), tile.getPackageName()); - // TODO: Match missed calls with matching Uris in addition to keys. - if (!visibleNotifications.containsKey(key)) { - if (DEBUG) Log.d(TAG, "No existing notifications for key:" + key.toString()); - return tile; + /** Removes all notification related fields from {@code tile}. */ + public static PeopleSpaceTile removeNotificationFields(PeopleSpaceTile tile) { + if (DEBUG) { + Log.i(TAG, "Removing any notification stored for tile Id: " + tile.getId()); } - if (DEBUG) Log.d(TAG, "Augmenting tile from visible notifications, key:" + key.toString()); - return augmentTileFromNotification(context, tile, visibleNotifications.get(key).getSbn()); + return tile + .toBuilder() + // Reset notification content. + .setNotificationKey(null) + .setNotificationContent(null) + .setNotificationDataUri(null) + .setMessagesCount(0) + // Reset missed calls category. + .setNotificationCategory(null) + .build(); } - /** Augments {@code tile} with the notification content from {@code sbn}. */ + /** + * Augments {@code tile} with the notification content from {@code notificationEntry} and + * {@code messagesCount}. + */ public static PeopleSpaceTile augmentTileFromNotification(Context context, PeopleSpaceTile tile, - StatusBarNotification sbn) { - Notification notification = sbn.getNotification(); - if (notification == null) { + NotificationEntry notificationEntry, int messagesCount) { + if (notificationEntry == null || notificationEntry.getSbn().getNotification() == null) { if (DEBUG) Log.d(TAG, "Notification is null"); - return tile; + return removeNotificationFields(tile); } - boolean isMissedCall = Objects.equals(notification.category, CATEGORY_MISSED_CALL); + Notification notification = notificationEntry.getSbn().getNotification(); + boolean isMissedCall = isMissedCall(notification); List<Notification.MessagingStyle.Message> messages = getMessagingStyleMessages(notification); if (!isMissedCall && ArrayUtils.isEmpty(messages)) { if (DEBUG) Log.d(TAG, "Notification has no content"); - return tile; + return removeNotificationFields(tile); } // messages are in chronological order from most recent to least. Notification.MessagingStyle.Message message = messages != null ? messages.get(0) : null; - int messagesCount = messages != null ? messages.size() : 0; // If it's a missed call notification and it doesn't include content, use fallback value, // otherwise, use notification content. boolean hasMessageText = message != null && !TextUtils.isEmpty(message.getText()); @@ -262,7 +272,7 @@ public class PeopleSpaceUtils { return tile .toBuilder() - .setNotificationKey(sbn.getKey()) + .setNotificationKey(notificationEntry.getSbn().getKey()) .setNotificationCategory(notification.category) .setNotificationContent(content) .setNotificationDataUri(dataUri) @@ -270,30 +280,6 @@ public class PeopleSpaceUtils { .build(); } - /** - * Returns {@link Notification.MessagingStyle.Message}s from the Notification in chronological - * order from most recent to least. - */ - @VisibleForTesting - public static List<Notification.MessagingStyle.Message> getMessagingStyleMessages( - Notification notification) { - if (notification == null) { - return null; - } - if (Notification.MessagingStyle.class.equals(notification.getNotificationStyle()) - && notification.extras != null) { - final Parcelable[] messages = notification.extras.getParcelableArray(EXTRA_MESSAGES); - if (!ArrayUtils.isEmpty(messages)) { - List<Notification.MessagingStyle.Message> sortedMessages = - Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages); - sortedMessages.sort(Collections.reverseOrder( - Comparator.comparing(Notification.MessagingStyle.Message::getTimestamp))); - return sortedMessages; - } - } - return null; - } - /** Returns a list sorted by ascending last interaction time from {@code stream}. */ public static List<PeopleSpaceTile> getSortedTiles(IPeopleManager peopleManager, LauncherApps launcherApps, UserManager userManager, @@ -467,7 +453,14 @@ public class PeopleSpaceUtils { /** Updates the current widget view with provided {@link PeopleSpaceTile}. */ public static void updateAppWidgetViews(AppWidgetManager appWidgetManager, Context context, int appWidgetId, PeopleSpaceTile tile, Bundle options) { - if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + ", " + tile.getUserName()); + if (tile == null) { + if (DEBUG) Log.d(TAG, "Widget: " + appWidgetId + ". Tile is null, skipping update"); + return; + } + if (DEBUG) { + Log.d(TAG, "Widget: " + appWidgetId + ", " + tile.getUserName() + ", " + + tile.getPackageName()); + } RemoteViews views = new PeopleTileViewHelper(context, tile, appWidgetId, options).getViews(); @@ -478,10 +471,24 @@ public class PeopleSpaceUtils { /** Updates tile in app widget options and the current view. */ public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager, Context context, int appWidgetId, PeopleSpaceTile tile) { + if (tile == null) { + Log.d(TAG, "Tile is null, skipping storage and update."); + return; + } Bundle options = AppWidgetOptionsHelper.setPeopleTile(appWidgetManager, appWidgetId, tile); updateAppWidgetViews(appWidgetManager, context, appWidgetId, tile, options); } + /** Wrapper around {@link #updateAppWidgetOptionsAndView} with optional tile as a parameter. */ + public static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager, + Context context, int appWidgetId, Optional<PeopleSpaceTile> optionalTile) { + if (!optionalTile.isPresent()) { + Log.d(TAG, "Tile is null, skipping storage and update."); + return; + } + updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, optionalTile.get()); + } + /** * Returns lookup keys for all contacts with a birthday today. * @@ -523,42 +530,6 @@ public class PeopleSpaceUtils { return lookupKeysWithBirthdaysToday; } - /** - * Returns a {@link RemoteViews} preview of a Conversation's People Tile. Returns null if one - * is not available. - */ - public static RemoteViews getPreview(Context context, IPeopleManager peopleManager, - LauncherApps launcherApps, NotificationEntryManager notificationEntryManager, - String shortcutId, UserHandle userHandle, String packageName, Bundle options) { - peopleManager = (peopleManager != null) ? peopleManager : IPeopleManager.Stub.asInterface( - ServiceManager.getService(Context.PEOPLE_SERVICE)); - launcherApps = (launcherApps != null) ? launcherApps - : context.getSystemService(LauncherApps.class); - if (peopleManager == null || launcherApps == null) { - return null; - } - - ConversationChannel channel; - try { - channel = peopleManager.getConversation( - packageName, userHandle.getIdentifier(), shortcutId); - } catch (Exception e) { - Log.w(TAG, "Exception getting tiles: " + e); - return null; - } - PeopleSpaceTile tile = PeopleSpaceUtils.getTile(channel, launcherApps); - - if (tile == null) { - if (DEBUG) Log.i(TAG, "No tile was returned"); - return null; - } - PeopleSpaceTile augmentedTile = augmentSingleTileFromVisibleNotifications( - context, tile, notificationEntryManager); - - if (DEBUG) Log.i(TAG, "Returning tile preview for shortcutId: " + shortcutId); - return new PeopleTileViewHelper(context, augmentedTile, 0, options).getViews(); - } - /** Returns the userId associated with a {@link PeopleSpaceTile} */ public static int getUserId(PeopleSpaceTile tile) { return tile.getUserHandle().getIdentifier(); diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java index 6b917c576fd8..dd89f749d1bc 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java @@ -71,7 +71,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -class PeopleTileViewHelper { +/** Functions that help creating the People tile layouts. */ +public class PeopleTileViewHelper { /** Turns on debugging information about People Space. */ public static final boolean DEBUG = true; private static final String TAG = "PeopleTileView"; @@ -115,7 +116,7 @@ class PeopleTileViewHelper { private Locale mLocale; private NumberFormat mIntegerFormat; - PeopleTileViewHelper(Context context, PeopleSpaceTile tile, + public PeopleTileViewHelper(Context context, PeopleSpaceTile tile, int appWidgetId, Bundle options) { mContext = context; mTile = tile; @@ -346,6 +347,7 @@ class PeopleTileViewHelper { private RemoteViews createMissedCallRemoteViews() { RemoteViews views = getViewForContentLayout(); views.setViewVisibility(R.id.predefined_icon, View.VISIBLE); + views.setViewVisibility(R.id.messages_count, View.GONE); setMaxLines(views); views.setTextViewText(R.id.text_content, mTile.getNotificationContent()); views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_phone_missed); @@ -546,7 +548,6 @@ class PeopleTileViewHelper { if (mLayoutSize == LAYOUT_SMALL) { views.setViewVisibility(R.id.predefined_icon, View.VISIBLE); views.setViewVisibility(R.id.name, View.GONE); - views.setViewVisibility(R.id.messages_count, View.GONE); } else { views.setViewVisibility(R.id.predefined_icon, View.GONE); views.setViewVisibility(R.id.name, View.VISIBLE); @@ -561,6 +562,7 @@ class PeopleTileViewHelper { views.setViewPadding(R.id.item, horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); } + views.setViewVisibility(R.id.messages_count, View.GONE); return views; } diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java index fb0dcc2bc50a..9fa6fc36e9d1 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java @@ -17,24 +17,25 @@ package com.android.systemui.people.widget; import static android.Manifest.permission.READ_CONTACTS; -import static android.app.Notification.CATEGORY_MISSED_CALL; -import static android.app.Notification.EXTRA_PEOPLE_LIST; +import static com.android.systemui.people.NotificationHelper.getContactUri; +import static com.android.systemui.people.NotificationHelper.getHighestPriorityNotification; +import static com.android.systemui.people.NotificationHelper.shouldMatchNotificationByUri; import static com.android.systemui.people.PeopleSpaceUtils.EMPTY_STRING; import static com.android.systemui.people.PeopleSpaceUtils.INVALID_USER_ID; import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; import static com.android.systemui.people.PeopleSpaceUtils.SHORTCUT_ID; import static com.android.systemui.people.PeopleSpaceUtils.USER_ID; import static com.android.systemui.people.PeopleSpaceUtils.augmentTileFromNotification; -import static com.android.systemui.people.PeopleSpaceUtils.getMessagingStyleMessages; -import static com.android.systemui.people.PeopleSpaceUtils.getStoredWidgetIds; +import static com.android.systemui.people.PeopleSpaceUtils.getMessagesCount; +import static com.android.systemui.people.PeopleSpaceUtils.getNotificationsByUri; +import static com.android.systemui.people.PeopleSpaceUtils.removeNotificationFields; import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetOptionsAndView; import static com.android.systemui.people.PeopleSpaceUtils.updateAppWidgetViews; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.INotificationManager; -import android.app.Notification; import android.app.NotificationChannel; import android.app.PendingIntent; import android.app.Person; @@ -67,10 +68,13 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Dependency; +import com.android.systemui.people.NotificationHelper; import com.android.systemui.people.PeopleSpaceUtils; +import com.android.systemui.people.PeopleTileViewHelper; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationListener.NotificationHandler; import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.util.ArrayList; import java.util.Collections; @@ -78,8 +82,10 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; +import java.util.Optional; import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; @@ -272,9 +278,10 @@ public class PeopleSpaceWidgetManager { private void updateWidgetsWithNotificationChangedInBackground(StatusBarNotification sbn, PeopleSpaceUtils.NotificationAction action) { try { - String sbnShortcutId = sbn.getShortcutId(); - if (sbnShortcutId == null) { - if (DEBUG) Log.d(TAG, "Sbn shortcut id is null"); + PeopleTileKey key = new PeopleTileKey( + sbn.getShortcutId(), sbn.getUser().getIdentifier(), sbn.getPackageName()); + if (!key.isValid()) { + Log.d(TAG, "Invalid key from sbn"); return; } int[] widgetIds = mAppWidgetManager.getAppWidgetIds( @@ -284,21 +291,15 @@ public class PeopleSpaceWidgetManager { Log.d(TAG, "No app widget ids returned"); return; } - PeopleTileKey key = new PeopleTileKey( - sbnShortcutId, - sbn.getUser().getIdentifier(), - sbn.getPackageName()); - if (!key.isValid()) { - Log.d(TAG, "Invalid key"); - return; - } synchronized (mLock) { - // First, update People Tiles associated with the Notification's package/shortcut. - Set<String> tilesUpdatedByKey = getStoredWidgetIds(mSharedPrefs, key); - updateWidgetIdsForNotificationAction(tilesUpdatedByKey, sbn, action); - - // Then, update People Tiles across other packages that use the same Uri. - updateTilesByUri(key, sbn, action); + Set<String> tilesUpdated = getMatchingKeyWidgetIds(key); + Set<String> tilesUpdatedByUri = getMatchingUriWidgetIds(sbn, action); + if (DEBUG) { + Log.d(TAG, "Widgets by key to be updated:" + tilesUpdated.toString()); + Log.d(TAG, "Widgets by URI to be updated:" + tilesUpdatedByUri.toString()); + } + tilesUpdated.addAll(tilesUpdatedByUri); + updateWidgetIdsBasedOnNotifications(tilesUpdated); } } catch (Exception e) { Log.e(TAG, "Throwing exception: " + e); @@ -306,36 +307,142 @@ public class PeopleSpaceWidgetManager { } /** Updates {@code widgetIdsToUpdate} with {@code action}. */ - private void updateWidgetIdsForNotificationAction(Set<String> widgetIdsToUpdate, - StatusBarNotification sbn, PeopleSpaceUtils.NotificationAction action) { - for (String widgetIdString : widgetIdsToUpdate) { - int widgetId = Integer.parseInt(widgetIdString); - PeopleSpaceTile storedTile = getTileForExistingWidget(widgetId); - if (storedTile == null) { - if (DEBUG) Log.d(TAG, "Could not find stored tile for notification"); - continue; + private void updateWidgetIdsBasedOnNotifications(Set<String> widgetIdsToUpdate) { + Log.d(TAG, "Fetching grouped notifications"); + try { + Map<PeopleTileKey, Set<NotificationEntry>> groupedNotifications = + getGroupedConversationNotifications(); + + widgetIdsToUpdate + .stream() + .map(Integer::parseInt) + .collect(Collectors.toMap( + Function.identity(), + id -> getAugmentedTileForExistingWidget(id, groupedNotifications))) + .forEach((id, tile) -> + updateAppWidgetOptionsAndView(mAppWidgetManager, mContext, id, tile)); + } catch (Exception e) { + Log.e(TAG, "Exception updating widgets: " + e); + } + } + + /** + * Augments {@code tile} based on notifications returned from {@code notificationEntryManager}. + */ + public PeopleSpaceTile augmentTileFromNotificationEntryManager(PeopleSpaceTile tile) { + Log.d(TAG, "Augmenting tile from NotificationEntryManager widget: " + tile.getId()); + Map<PeopleTileKey, Set<NotificationEntry>> notifications = + getGroupedConversationNotifications(); + String contactUri = null; + if (tile.getContactUri() != null) { + contactUri = tile.getContactUri().toString(); + } + return augmentTileFromNotifications(tile, contactUri, notifications); + } + + /** Returns active and pending notifications grouped by {@link PeopleTileKey}. */ + public Map<PeopleTileKey, Set<NotificationEntry>> getGroupedConversationNotifications() { + List<NotificationEntry> notifications = + new ArrayList<>(mNotificationEntryManager.getVisibleNotifications()); + Iterable<NotificationEntry> pendingNotifications = + mNotificationEntryManager.getPendingNotificationsIterator(); + for (NotificationEntry entry : pendingNotifications) { + notifications.add(entry); + } + if (DEBUG) Log.d(TAG, "Number of total notifications: " + notifications.size()); + Map<PeopleTileKey, Set<NotificationEntry>> groupedNotifications = + notifications + .stream() + .filter(entry -> NotificationHelper.isValid(entry) + && NotificationHelper.isMissedCallOrHasContent(entry)) + .collect(Collectors.groupingBy( + PeopleTileKey::new, + Collectors.mapping(Function.identity(), Collectors.toSet()))); + if (DEBUG) { + Log.d(TAG, "Number of grouped conversation notifications keys: " + + groupedNotifications.keySet().size()); + } + return groupedNotifications; + } + + /** Augments {@code tile} based on {@code notifications}, matching {@code contactUri}. */ + public PeopleSpaceTile augmentTileFromNotifications(PeopleSpaceTile tile, String contactUri, + Map<PeopleTileKey, Set<NotificationEntry>> notifications) { + if (DEBUG) Log.d(TAG, "Augmenting tile from notifications. Tile id: " + tile.getId()); + boolean hasReadContactsPermission = mPackageManager.checkPermission(READ_CONTACTS, + tile.getPackageName()) == PackageManager.PERMISSION_GRANTED; + + List<NotificationEntry> notificationsByUri = new ArrayList<>(); + if (hasReadContactsPermission) { + notificationsByUri = getNotificationsByUri(mPackageManager, contactUri, notifications); + if (!notificationsByUri.isEmpty()) { + if (DEBUG) { + Log.d(TAG, "Number of notifications matched by contact URI: " + + notificationsByUri.size()); + } } - if (DEBUG) Log.d(TAG, "Storing notification change, key:" + sbn.getKey()); - updateStorageAndViewWithNotificationData(sbn, action, widgetId, - storedTile); } + + PeopleTileKey key = new PeopleTileKey(tile); + Set<NotificationEntry> allNotifications = notifications.get(key); + if (allNotifications == null) { + allNotifications = new HashSet<>(); + } + if (allNotifications.isEmpty() && notificationsByUri.isEmpty()) { + if (DEBUG) Log.d(TAG, "No existing notifications for tile: " + key); + return removeNotificationFields(tile); + } + + // Merge notifications matched by key and by contact URI. + allNotifications.addAll(notificationsByUri); + if (DEBUG) Log.d(TAG, "Total notifications matching tile: " + allNotifications.size()); + + int messagesCount = getMessagesCount(allNotifications); + NotificationEntry highestPriority = getHighestPriorityNotification(allNotifications); + + if (DEBUG) Log.d(TAG, "Augmenting tile from notification, key: " + key.toString()); + return augmentTileFromNotification(mContext, tile, highestPriority, messagesCount); + } + + /** Returns an augmented tile for an existing widget. */ + @Nullable + public Optional<PeopleSpaceTile> getAugmentedTileForExistingWidget(int widgetId, + Map<PeopleTileKey, Set<NotificationEntry>> notifications) { + Log.d(TAG, "Augmenting tile for widget: " + widgetId); + PeopleSpaceTile tile = getTileForExistingWidget(widgetId); + if (tile == null) { + return Optional.empty(); + } + String contactUriString = mSharedPrefs.getString(String.valueOf(widgetId), null); + // Should never be null, but using ofNullable for extra safety. + return Optional.ofNullable( + augmentTileFromNotifications(tile, contactUriString, notifications)); + } + + /** Returns stored widgets for the conversation specified. */ + public Set<String> getMatchingKeyWidgetIds(PeopleTileKey key) { + if (!key.isValid()) { + return new HashSet<>(); + } + return new HashSet<>(mSharedPrefs.getStringSet(key.toString(), new HashSet<>())); } /** - * Updates tiles with matched Uris, dependent on the {@code action}. + * Updates in-memory map of tiles with matched Uris, dependent on the {@code action}. * * <p>If the notification was added, adds the notification based on the contact Uri within * {@code sbn}. * <p>If the notification was removed, removes the notification based on the in-memory map of * widgets previously updated by Uri (since the contact Uri is stripped from the {@code sbn}). */ - private void updateTilesByUri(PeopleTileKey key, StatusBarNotification sbn, + @Nullable + private Set<String> getMatchingUriWidgetIds(StatusBarNotification sbn, PeopleSpaceUtils.NotificationAction action) { if (action.equals(PeopleSpaceUtils.NotificationAction.POSTED)) { - Set<String> widgetIdsUpdatedByUri = supplementTilesByUri(sbn, action, key); + Set<String> widgetIdsUpdatedByUri = fetchMatchingUriWidgetIds(sbn); if (widgetIdsUpdatedByUri != null && !widgetIdsUpdatedByUri.isEmpty()) { - if (DEBUG) Log.d(TAG, "Added due to uri: " + widgetIdsUpdatedByUri); mNotificationKeyToWidgetIdsMatchedByUri.put(sbn.getKey(), widgetIdsUpdatedByUri); + return widgetIdsUpdatedByUri; } } else { // Remove the notification on any widgets where the notification was added @@ -343,21 +450,16 @@ public class PeopleSpaceWidgetManager { Set<String> widgetsPreviouslyUpdatedByUri = mNotificationKeyToWidgetIdsMatchedByUri.remove(sbn.getKey()); if (widgetsPreviouslyUpdatedByUri != null && !widgetsPreviouslyUpdatedByUri.isEmpty()) { - if (DEBUG) Log.d(TAG, "Remove due to uri: " + widgetsPreviouslyUpdatedByUri); - updateWidgetIdsForNotificationAction(widgetsPreviouslyUpdatedByUri, sbn, - action); + return widgetsPreviouslyUpdatedByUri; } } + return new HashSet<>(); } - /** - * Retrieves from storage any tiles with the same contact Uri as linked via the {@code sbn}. - * Supplements the tiles with the notification content only if they still have {@link - * android.Manifest.permission.READ_CONTACTS} permission. - */ + /** Fetches widget Ids that match the contact URI in {@code sbn}. */ @Nullable - private Set<String> supplementTilesByUri(StatusBarNotification sbn, - PeopleSpaceUtils.NotificationAction notificationAction, PeopleTileKey key) { + private Set<String> fetchMatchingUriWidgetIds(StatusBarNotification sbn) { + // Check if it's a missed call notification if (!shouldMatchNotificationByUri(sbn)) { if (DEBUG) Log.d(TAG, "Should not supplement conversation"); return null; @@ -377,80 +479,7 @@ public class PeopleSpaceWidgetManager { if (DEBUG) Log.d(TAG, "No tiles for contact"); return null; } - - if (mPackageManager.checkPermission(READ_CONTACTS, - sbn.getPackageName()) != PackageManager.PERMISSION_GRANTED) { - if (DEBUG) Log.d(TAG, "Notifying app missing permissions"); - return null; - } - - Set<String> widgetIdsUpdatedByUri = new HashSet<>(); - for (String widgetIdString : storedWidgetIdsByUri) { - int widgetId = Integer.parseInt(widgetIdString); - PeopleSpaceTile storedTile = getTileForExistingWidget(widgetId); - // Don't update a widget already updated. - if (key.equals(new PeopleTileKey(storedTile))) { - continue; - } - if (storedTile == null || mPackageManager.checkPermission(READ_CONTACTS, - storedTile.getPackageName()) != PackageManager.PERMISSION_GRANTED) { - if (DEBUG) Log.d(TAG, "Cannot supplement tile: " + storedTile.getUserName()); - continue; - } - if (DEBUG) Log.d(TAG, "Adding notification by uri: " + sbn.getKey()); - updateStorageAndViewWithNotificationData(sbn, notificationAction, - widgetId, storedTile); - widgetIdsUpdatedByUri.add(String.valueOf(widgetId)); - } - return widgetIdsUpdatedByUri; - } - - /** - * Try to retrieve a valid Uri via {@code sbn}, falling back to the {@code - * contactUriFromShortcut} if valid. - */ - @Nullable - private String getContactUri(StatusBarNotification sbn) { - // First, try to get a Uri from the Person directly set on the Notification. - ArrayList<Person> people = sbn.getNotification().extras.getParcelableArrayList( - EXTRA_PEOPLE_LIST); - if (people != null && people.get(0) != null) { - String contactUri = people.get(0).getUri(); - if (contactUri != null && !contactUri.isEmpty()) { - return contactUri; - } - } - - // Then, try to get a Uri from the Person set on the Notification message. - List<Notification.MessagingStyle.Message> messages = - getMessagingStyleMessages(sbn.getNotification()); - if (messages != null && !messages.isEmpty()) { - Notification.MessagingStyle.Message message = messages.get(0); - Person sender = message.getSenderPerson(); - if (sender != null && sender.getUri() != null && !sender.getUri().isEmpty()) { - return sender.getUri(); - } - } - - return null; - } - - /** - * Returns whether a notification should be matched to other Tiles by Uri. - * - * <p>Currently only matches missed calls. - */ - private boolean shouldMatchNotificationByUri(StatusBarNotification sbn) { - Notification notification = sbn.getNotification(); - if (notification == null) { - if (DEBUG) Log.d(TAG, "Notification is null"); - return false; - } - if (!Objects.equals(notification.category, CATEGORY_MISSED_CALL)) { - if (DEBUG) Log.d(TAG, "Not missed call"); - return false; - } - return true; + return storedWidgetIdsByUri; } /** @@ -461,7 +490,7 @@ public class PeopleSpaceWidgetManager { synchronized (mLock) { PeopleTileKey key = new PeopleTileKey( info.getId(), info.getUserId(), info.getPackage()); - Set<String> storedWidgetIds = getStoredWidgetIds(mSharedPrefs, key); + Set<String> storedWidgetIds = getMatchingKeyWidgetIds(key); for (String widgetIdString : storedWidgetIds) { if (DEBUG) { Log.d(TAG, @@ -469,7 +498,7 @@ public class PeopleSpaceWidgetManager { + info.getLabel()); } updateStorageAndViewWithConversationData(conversation, - Integer.valueOf(widgetIdString)); + Integer.parseInt(widgetIdString)); } } } @@ -505,34 +534,6 @@ public class PeopleSpaceWidgetManager { } /** - * Update {@code appWidgetId} with the new data provided by {@code sbn}. - */ - private void updateStorageAndViewWithNotificationData( - StatusBarNotification sbn, - PeopleSpaceUtils.NotificationAction notificationAction, - int appWidgetId, PeopleSpaceTile storedTile) { - if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) { - if (DEBUG) Log.i(TAG, "Adding notification to storage, appWidgetId: " + appWidgetId); - storedTile = augmentTileFromNotification(mContext, storedTile, sbn); - } else if (Objects.equals(storedTile.getNotificationKey(), sbn.getKey())) { - if (DEBUG) { - Log.i(TAG, "Removing notification from storage, appWidgetId: " + appWidgetId); - } - storedTile = storedTile - .toBuilder() - // Reset notification content. - .setNotificationKey(null) - .setNotificationContent(null) - .setNotificationDataUri(null) - .setMessagesCount(0) - // Reset missed calls category. - .setNotificationCategory(null) - .build(); - } - updateAppWidgetOptionsAndView(mAppWidgetManager, mContext, appWidgetId, storedTile); - } - - /** * Attaches the manager to the pipeline, making it ready to receive events. Should only be * called once. */ @@ -615,22 +616,10 @@ public class PeopleSpaceWidgetManager { public void addNewWidget(int appWidgetId, PeopleTileKey key) { if (DEBUG) Log.d(TAG, "addNewWidget called with key for appWidgetId: " + appWidgetId); PeopleSpaceTile tile = getTileFromPersistentStorage(key); - tile = PeopleSpaceUtils.augmentSingleTileFromVisibleNotifications( - mContext, tile, mNotificationEntryManager); - if (tile != null) { - addNewWidget(appWidgetId, tile); - } - } - - /** - * Adds a widget based on {@code tile} mapped to {@code appWidgetId}. - * The tile provided should already be augmented. - */ - public void addNewWidget(int appWidgetId, PeopleSpaceTile tile) { - if (DEBUG) Log.d(TAG, "addNewWidget called for appWidgetId: " + appWidgetId); if (tile == null) { return; } + tile = augmentTileFromNotificationEntryManager(tile); PeopleTileKey existingKeyIfStored; synchronized (mLock) { @@ -648,7 +637,6 @@ public class PeopleSpaceWidgetManager { synchronized (mLock) { if (DEBUG) Log.d(TAG, "Add storage for : " + tile.getId()); - PeopleTileKey key = new PeopleTileKey(tile); PeopleSpaceUtils.setSharedPreferencesStorageForTile(mContext, key, appWidgetId, tile.getContactUri()); } @@ -780,8 +768,7 @@ public class PeopleSpaceWidgetManager { public boolean requestPinAppWidget(ShortcutInfo shortcutInfo, Bundle options) { if (DEBUG) Log.d(TAG, "Requesting pin widget, shortcutId: " + shortcutInfo.getId()); - RemoteViews widgetPreview = PeopleSpaceUtils.getPreview(mContext, mIPeopleManager, - mLauncherApps, mNotificationEntryManager, shortcutInfo.getId(), + RemoteViews widgetPreview = getPreview(shortcutInfo.getId(), shortcutInfo.getUserHandle(), shortcutInfo.getPackage(), options); if (widgetPreview == null) { Log.w(TAG, "Skipping pinning widget: no tile for shortcutId: " + shortcutInfo.getId()); @@ -811,8 +798,6 @@ public class PeopleSpaceWidgetManager { List<PeopleSpaceTile> priorityTiles = PeopleSpaceUtils.getSortedTiles(mIPeopleManager, mLauncherApps, mUserManager, priorityConversations); - priorityTiles = PeopleSpaceUtils.augmentTilesFromVisibleNotifications( - mContext, priorityTiles, mNotificationEntryManager); return priorityTiles; } @@ -839,9 +824,33 @@ public class PeopleSpaceWidgetManager { List<PeopleSpaceTile> recentTiles = PeopleSpaceUtils.getSortedTiles(mIPeopleManager, mLauncherApps, mUserManager, mergedStream); - - recentTiles = PeopleSpaceUtils.augmentTilesFromVisibleNotifications( - mContext, recentTiles, mNotificationEntryManager); return recentTiles; } + + /** + * Returns a {@link RemoteViews} preview of a Conversation's People Tile. Returns null if one + * is not available. + */ + public RemoteViews getPreview(String shortcutId, UserHandle userHandle, String packageName, + Bundle options) { + PeopleSpaceTile tile; + ConversationChannel channel; + try { + channel = mIPeopleManager.getConversation( + packageName, userHandle.getIdentifier(), shortcutId); + tile = PeopleSpaceUtils.getTile(channel, mLauncherApps); + } catch (Exception e) { + Log.w(TAG, "Exception getting tiles: " + e); + return null; + } + if (tile == null) { + if (DEBUG) Log.i(TAG, "No tile was returned"); + return null; + } + + PeopleSpaceTile augmentedTile = augmentTileFromNotificationEntryManager(tile); + + if (DEBUG) Log.i(TAG, "Returning tile preview for shortcutId: " + shortcutId); + return new PeopleTileViewHelper(mContext, augmentedTile, 0, options).getViews(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java new file mode 100644 index 000000000000..7cddc3f8e82d --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/people/NotificationHelperTest.java @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.systemui.people; + +import static android.app.Notification.CATEGORY_MISSED_CALL; + +import static com.android.systemui.people.NotificationHelper.getHighestPriorityNotification; +import static com.android.systemui.people.NotificationHelper.getMessagingStyleMessages; +import static com.android.systemui.people.NotificationHelper.isMissedCall; +import static com.android.systemui.people.NotificationHelper.isMissedCallOrHasContent; +import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.app.Notification; +import android.app.Person; +import android.content.pm.ShortcutInfo; +import android.net.Uri; +import android.os.UserHandle; +import android.service.notification.StatusBarNotification; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.internal.util.ArrayUtils; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.SbnBuilder; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.List; +import java.util.Set; + +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class NotificationHelperTest extends SysuiTestCase { + private static final String SHORTCUT_ID_1 = "101"; + private static final String SHORTCUT_ID_2 = "102"; + + private static final String NOTIFICATION_TEXT_1 = "notification_text_1"; + private static final String NOTIFICATION_TEXT_2 = "notification_text_2"; + private static final String NOTIFICATION_TEXT_3 = "notification_text_3"; + private static final Uri URI = Uri.parse("fake_uri"); + private static final Person PERSON = new Person.Builder() + .setName("name") + .setKey("abc") + .setUri(URI.toString()) + .setBot(false) + .build(); + + private final Notification mNotification1 = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_1) + .setStyle(new Notification.MessagingStyle(PERSON) + .addMessage(new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_1, 0, PERSON)) + .addMessage(new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_2, 20, PERSON)) + .addMessage(new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_3, 10, PERSON)) + ) + .build(); + + private final Notification mNotification2 = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_1) + .setStyle(new Notification.MessagingStyle(PERSON) + .addMessage(new Notification.MessagingStyle.Message( + NOTIFICATION_TEXT_1, 0, PERSON)) + ) + .build(); + + private final Notification mNoContentNotification = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_1) + .setStyle(new Notification.MessagingStyle(PERSON)) + .build(); + + private final Notification mMissedCallNotification = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_2) + .setCategory(CATEGORY_MISSED_CALL) + .setStyle(new Notification.MessagingStyle(PERSON)) + .build(); + + private final NotificationEntry mNotificationEntry1 = new NotificationEntryBuilder() + .setNotification(mNotification1) + .setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).build()) + .setUser(UserHandle.of(0)) + .setPkg(PACKAGE_NAME) + .build(); + + private final NotificationEntry mNotificationEntry2 = new NotificationEntryBuilder() + .setNotification(mNotification2) + .setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).build()) + .setUser(UserHandle.of(0)) + .setPkg(PACKAGE_NAME) + .build(); + + + private final NotificationEntry mMissedCallNotificationEntry = new NotificationEntryBuilder() + .setNotification(mMissedCallNotification) + .setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).build()) + .setUser(UserHandle.of(0)) + .setPkg(PACKAGE_NAME) + .build(); + + private final NotificationEntry mNoContentNotificationEntry = new NotificationEntryBuilder() + .setNotification(mNoContentNotification) + .setShortcutInfo(new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).build()) + .setUser(UserHandle.of(0)) + .setPkg(PACKAGE_NAME) + .build(); + + @Test + public void testGetMessagingStyleMessagesNoMessage() { + Notification notification = new Notification.Builder(mContext, "test") + .setContentTitle("TEST_TITLE") + .setContentText("TEST_TEXT") + .setShortcutId(SHORTCUT_ID_1) + .build(); + StatusBarNotification sbn = new SbnBuilder() + .setNotification(notification) + .build(); + + List<Notification.MessagingStyle.Message> messages = + getMessagingStyleMessages(sbn.getNotification()); + + assertThat(ArrayUtils.isEmpty(messages)).isTrue(); + } + + @Test + public void testGetMessagingStyleMessages() { + StatusBarNotification sbn = new SbnBuilder() + .setNotification(mNotification1) + .build(); + + List<Notification.MessagingStyle.Message> messages = + getMessagingStyleMessages(sbn.getNotification()); + + assertThat(messages.size()).isEqualTo(3); + assertThat(messages.get(0).getText().toString()).isEqualTo(NOTIFICATION_TEXT_2); + } + + @Test + public void testIsMissedCall_notMissedCall() { + assertFalse(isMissedCall(mNotificationEntry1)); + } + + @Test + public void testIsMissedCall_missedCall() { + assertTrue(isMissedCall(mMissedCallNotificationEntry)); + } + + @Test + public void testisMissedCallOrHasContent_NoContent() { + assertFalse(isMissedCallOrHasContent(mNoContentNotificationEntry)); + } + + @Test + public void testisMissedCallOrHasContent_Hasontent() { + assertTrue(isMissedCallOrHasContent(mNotificationEntry1)); + } + + @Test + public void testGetHighestPriorityNotification_missedCallHigherPriority() { + Set<NotificationEntry> notifications = Set.of( + mNotificationEntry1, mMissedCallNotificationEntry); + + assertThat(getHighestPriorityNotification(notifications)) + .isEqualTo(mMissedCallNotificationEntry); + } + + @Test + public void testGetHighestPriorityNotification_moreRecentLastMessage() { + Set<NotificationEntry> notifications = Set.of( + mNotificationEntry1, mNotificationEntry2); + + assertThat(getHighestPriorityNotification(notifications)) + .isEqualTo(mNotificationEntry1); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTest.java index 24a63e7a2c73..50ab1c73227e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTest.java @@ -18,12 +18,11 @@ package com.android.systemui.people; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import android.app.people.ConversationChannel; -import android.app.people.IPeopleManager; -import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.net.Uri; @@ -36,8 +35,8 @@ import android.widget.RemoteViews; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.people.widget.PeopleSpaceWidgetManager; import com.android.systemui.shared.system.PeopleProviderUtils; -import com.android.systemui.statusbar.notification.NotificationEntryManager; import junit.framework.Assert; @@ -69,13 +68,11 @@ public class PeopleProviderTest extends SysuiTestCase { private Bundle mExtras = new Bundle(); @Mock - private LauncherApps mLauncherApps; - @Mock private PackageManager mPackageManager; @Mock - private IPeopleManager mPeopleManager; + private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager; @Mock - private NotificationEntryManager mNotificationEntryManager; + private RemoteViews mRemoteViews; @Before public void setUp() throws Exception { @@ -85,9 +82,7 @@ public class PeopleProviderTest extends SysuiTestCase { PeopleProviderTestable provider = new PeopleProviderTestable(); provider.initializeForTesting( mContext, PeopleProviderUtils.PEOPLE_PROVIDER_AUTHORITY); - provider.setLauncherApps(mLauncherApps); - provider.setPeopleManager(mPeopleManager); - provider.setNotificationEntryManager(mNotificationEntryManager); + provider.setPeopleSpaceWidgetManager(mPeopleSpaceWidgetManager); mContext.getContentResolver().addProvider( PeopleProviderUtils.PEOPLE_PROVIDER_AUTHORITY, provider); @@ -95,9 +90,9 @@ public class PeopleProviderTest extends SysuiTestCase { PeopleProviderUtils.GET_PEOPLE_TILE_PREVIEW_PERMISSION, PackageManager.PERMISSION_GRANTED); - when(mPeopleManager.getConversation( - eq(PACKAGE_NAME_A), eq(USER_HANDLE_A.getIdentifier()), eq(SHORTCUT_ID_A))) - .thenReturn(mConversationChannel); + when(mPeopleSpaceWidgetManager.getPreview( + eq(SHORTCUT_ID_A), eq(USER_HANDLE_A), eq(PACKAGE_NAME_A), any())) + .thenReturn(mRemoteViews); mExtras.putString(PeopleProviderUtils.EXTRAS_KEY_SHORTCUT_ID, SHORTCUT_ID_A); mExtras.putString(PeopleProviderUtils.EXTRAS_KEY_PACKAGE_NAME, PACKAGE_NAME_A); @@ -146,8 +141,8 @@ public class PeopleProviderTest extends SysuiTestCase { @Test public void testPermissionGrantedNoConversationForShortcutReturnsNull() throws RemoteException { - when(mPeopleManager.getConversation( - eq(PACKAGE_NAME_A), eq(USER_HANDLE_A.getIdentifier()), eq(SHORTCUT_ID_A))) + when(mPeopleSpaceWidgetManager.getPreview( + eq(SHORTCUT_ID_A), eq(USER_HANDLE_A), eq(PACKAGE_NAME_A), any())) .thenReturn(null); try { Bundle result = mContext.getContentResolver().call( diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java index 6834fa54a084..3e6d6746a997 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleProviderTestable.java @@ -16,12 +16,10 @@ package com.android.systemui.people; -import android.app.people.IPeopleManager; import android.content.Context; -import android.content.pm.LauncherApps; import android.content.pm.ProviderInfo; -import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.people.widget.PeopleSpaceWidgetManager; public class PeopleProviderTestable extends PeopleProvider { @@ -32,15 +30,7 @@ public class PeopleProviderTestable extends PeopleProvider { attachInfoForTesting(context, info); } - void setLauncherApps(LauncherApps launcherApps) { - mLauncherApps = launcherApps; - } - - void setPeopleManager(IPeopleManager peopleManager) { - mPeopleManager = peopleManager; - } - - void setNotificationEntryManager(NotificationEntryManager notificationEntryManager) { - mNotificationEntryManager = notificationEntryManager; + void setPeopleSpaceWidgetManager(PeopleSpaceWidgetManager peopleSpaceWidgetManager) { + mPeopleSpaceWidgetManager = peopleSpaceWidgetManager; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java index 81ca4c898290..c929073d9a09 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java @@ -51,19 +51,15 @@ import android.net.Uri; import android.os.Bundle; import android.os.UserHandle; import android.provider.ContactsContract; -import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import android.util.DisplayMetrics; import androidx.test.filters.SmallTest; import com.android.internal.appwidget.IAppWidgetService; -import com.android.internal.util.ArrayUtils; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; -import com.android.systemui.people.widget.PeopleTileKey; import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; @@ -228,41 +224,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { } @Test - public void testGetMessagingStyleMessagesNoMessage() { - Notification notification = new Notification.Builder(mContext, "test") - .setContentTitle("TEST_TITLE") - .setContentText("TEST_TEXT") - .setShortcutId(SHORTCUT_ID_1) - .build(); - StatusBarNotification sbn = new SbnBuilder() - .setNotification(notification) - .build(); - - List<Notification.MessagingStyle.Message> messages = - PeopleSpaceUtils.getMessagingStyleMessages(sbn.getNotification()); - - assertThat(ArrayUtils.isEmpty(messages)).isTrue(); - } - - @Test - public void testGetMessagingStyleMessages() { - StatusBarNotification sbn = new SbnBuilder() - .setNotification(mNotification1) - .build(); - - List<Notification.MessagingStyle.Message> messages = - PeopleSpaceUtils.getMessagingStyleMessages(sbn.getNotification()); - - assertThat(messages.size()).isEqualTo(3); - assertThat(messages.get(0).getText().toString()).isEqualTo(NOTIFICATION_TEXT_2); - } - - @Test public void testAugmentTileFromNotification() { - StatusBarNotification sbn = new SbnBuilder() - .setNotification(mNotification1) - .build(); - PeopleSpaceTile tile = new PeopleSpaceTile .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent()) @@ -270,17 +232,13 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { .setUserHandle(new UserHandle(0)) .build(); PeopleSpaceTile actual = PeopleSpaceUtils - .augmentTileFromNotification(mContext, tile, sbn); + .augmentTileFromNotification(mContext, tile, mNotificationEntry1, 0); assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2); } @Test public void testAugmentTileFromNotificationNoContent() { - StatusBarNotification sbn = new SbnBuilder() - .setNotification(mNotification3) - .build(); - PeopleSpaceTile tile = new PeopleSpaceTile .Builder(SHORTCUT_ID_3, "userName", ICON, new Intent()) @@ -288,107 +246,12 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { .setUserHandle(new UserHandle(0)) .build(); PeopleSpaceTile actual = PeopleSpaceUtils - .augmentTileFromNotification(mContext, tile, sbn); + .augmentTileFromNotification(mContext, tile, mNotificationEntry3, 0); assertThat(actual.getNotificationContent()).isEqualTo(null); } @Test - public void testAugmentTileFromVisibleNotifications() { - PeopleSpaceTile tile = - new PeopleSpaceTile - .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent()) - .setPackageName(PACKAGE_NAME) - .setUserHandle(new UserHandle(0)) - .build(); - PeopleSpaceTile actual = PeopleSpaceUtils - .augmentTileFromVisibleNotifications(mContext, tile, - Map.of(new PeopleTileKey(mNotificationEntry1), mNotificationEntry1)); - - assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_TEXT_2); - } - - @Test - public void testAugmentTileFromVisibleNotificationsDifferentShortcutId() { - PeopleSpaceTile tile = - new PeopleSpaceTile - .Builder(SHORTCUT_ID_4, "userName", ICON, new Intent()) - .setPackageName(PACKAGE_NAME) - .setUserHandle(new UserHandle(0)) - .build(); - PeopleSpaceTile actual = PeopleSpaceUtils - .augmentTileFromVisibleNotifications(mContext, tile, - Map.of(new PeopleTileKey(mNotificationEntry1), mNotificationEntry1)); - - assertThat(actual.getNotificationContent()).isEqualTo(null); - } - - @Test - public void testAugmentTilesFromVisibleNotificationsSingleTile() { - PeopleSpaceTile tile = - new PeopleSpaceTile - .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent()) - .setPackageName(PACKAGE_NAME) - .setUserHandle(new UserHandle(0)) - .build(); - List<PeopleSpaceTile> actualList = PeopleSpaceUtils - .augmentTilesFromVisibleNotifications( - mContext, List.of(tile), mNotificationEntryManager); - - assertThat(actualList.size()).isEqualTo(1); - assertThat(actualList.get(0).getNotificationContent().toString()) - .isEqualTo(NOTIFICATION_TEXT_2); - - verify(mNotificationEntryManager, times(1)).getVisibleNotifications(); - } - - @Test - public void testAugmentTilesFromVisibleNotificationsMultipleTiles() { - PeopleSpaceTile tile1 = - new PeopleSpaceTile - .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent()) - .setPackageName(PACKAGE_NAME) - .setUserHandle(new UserHandle(0)) - .build(); - PeopleSpaceTile tile2 = - new PeopleSpaceTile - .Builder(SHORTCUT_ID_2, "userName2", ICON, new Intent()) - .setPackageName(PACKAGE_NAME) - .setUserHandle(new UserHandle(0)) - .build(); - List<PeopleSpaceTile> actualList = PeopleSpaceUtils - .augmentTilesFromVisibleNotifications(mContext, List.of(tile1, tile2), - mNotificationEntryManager); - - assertThat(actualList.size()).isEqualTo(2); - assertThat(actualList.get(0).getNotificationContent().toString()) - .isEqualTo(NOTIFICATION_TEXT_2); - assertThat(actualList.get(1).getNotificationContent().toString()) - .isEqualTo(NOTIFICATION_TEXT_4); - - verify(mNotificationEntryManager, times(1)).getVisibleNotifications(); - } - - @Test - public void testAugmentSingleTileFromVisibleNotificationsSingleTile() { - PeopleSpaceTile tile = - new PeopleSpaceTile - .Builder(SHORTCUT_ID_1, "userName", ICON, new Intent()) - .setPackageName(PACKAGE_NAME) - .setUserHandle(new UserHandle(0)) - .build(); - PeopleSpaceTile augmentedTile = PeopleSpaceUtils - .augmentSingleTileFromVisibleNotifications( - mContext, tile, mNotificationEntryManager); - - assertThat(augmentedTile).isNotNull(); - assertThat(augmentedTile.getNotificationContent().toString()) - .isEqualTo(NOTIFICATION_TEXT_2); - - verify(mNotificationEntryManager, times(1)).getVisibleNotifications(); - } - - @Test public void testDoNotUpdateSingleConversationAppWidgetWhenNotBirthday() { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; when(mMockCursor.moveToNext()).thenReturn(true, false); diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java index 1ab5d341ab90..725e5d4523a7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java @@ -68,6 +68,7 @@ import android.content.pm.ShortcutInfo; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; +import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.service.notification.ConversationChannelWrapper; @@ -86,6 +87,7 @@ import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.collection.NoManSimulator; import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.util.time.FakeSystemClock; @@ -99,8 +101,10 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -124,7 +128,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { private static final String SHORTCUT_ID = "101"; private static final String OTHER_SHORTCUT_ID = "102"; private static final String NOTIFICATION_KEY = "0|com.android.systemui.tests|0|null|0"; - private static final String NOTIFICATION_CONTENT = "message text"; + private static final String NOTIFICATION_CONTENT_1 = "message text 1"; private static final Uri URI = Uri.parse("fake_uri"); private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android); private static final PeopleTileKey KEY = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); @@ -140,7 +144,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .setPackageName(TEST_PACKAGE_A) .setUserHandle(new UserHandle(0)) .setNotificationKey(NOTIFICATION_KEY + "1") - .setNotificationContent(NOTIFICATION_CONTENT) + .setNotificationContent(NOTIFICATION_CONTENT_1) .setNotificationDataUri(URI) .setContactUri(URI) .build(); @@ -154,8 +158,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { // Same contact uri. .setContactUri(URI) .build(); - private final ShortcutInfo mShortcutInfo = new ShortcutInfo.Builder(mContext, - SHORTCUT_ID).setLongLabel("name").build(); + private ShortcutInfo mShortcutInfo; + private NotificationEntry mNotificationEntry; private PeopleSpaceWidgetManager mManager; @@ -215,6 +219,17 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT))) .thenReturn(new Bundle()); when(mUserManager.isQuietModeEnabled(any())).thenReturn(false); + + when(mMockContext.getPackageName()).thenReturn(TEST_PACKAGE_A); + when(mMockContext.getUserId()).thenReturn(0); + mShortcutInfo = new ShortcutInfo.Builder(mMockContext, + SHORTCUT_ID).setLongLabel("name").build(); + mNotificationEntry = new NotificationEntryBuilder() + .setSbn(createNotification( + SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false)) + .setId(1) + .setShortcutInfo(mShortcutInfo) + .build(); } @Test @@ -490,7 +505,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { ACTIVITY_GAME).setDescription("Playing a game!").build(); ConversationStatus status2 = new ConversationStatus.Builder(OTHER_SHORTCUT_ID, ACTIVITY_BIRTHDAY).build(); - ConversationChannel conversationChannel = getConversationWithShortcutId(OTHER_SHORTCUT_ID, + ConversationChannel conversationChannel = getConversationWithShortcutId( + new PeopleTileKey(OTHER_SHORTCUT_ID, 0, TEST_PACKAGE_A), Arrays.asList(status1, status2)); mManager.updateWidgetsWithConversationChanged(conversationChannel); mClock.advanceTime(MIN_LINGER_DURATION); @@ -508,7 +524,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { ConversationStatus status = new ConversationStatus.Builder(SHORTCUT_ID, ACTIVITY_GAME).setDescription("Playing a game!").build(); - ConversationChannel conversationChannel = getConversationWithShortcutId(SHORTCUT_ID, + ConversationChannel conversationChannel = getConversationWithShortcutId( + new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A), Arrays.asList(status)); mManager.updateWidgetsWithConversationChanged(conversationChannel); mClock.advanceTime(MIN_LINGER_DURATION); @@ -529,8 +546,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { ConversationStatus status = new ConversationStatus.Builder(SHORTCUT_ID, ACTIVITY_ANNIVERSARY).build(); - ConversationChannel conversationChannel = getConversationWithShortcutId(SHORTCUT_ID, - Arrays.asList(status)); + ConversationChannel conversationChannel = getConversationWithShortcutId( + new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A), Arrays.asList(status)); mManager.updateWidgetsWithConversationChanged(conversationChannel); mClock.advanceTime(MIN_LINGER_DURATION); @@ -550,11 +567,15 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { public void testUpdateNotificationPostedIfExistingTile() throws Exception { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() .setSbn(createNotification( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ false)) - .setId(1)); + .setShortcutInfo(mShortcutInfo) + .setId(1); + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); mClock.advanceTime(MIN_LINGER_DURATION); verify(mAppWidgetManager, times(1)) @@ -563,7 +584,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { Bundle bundle = mBundleArgumentCaptor.getValue(); PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); - assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT); + assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); } @@ -620,11 +641,15 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { throws Exception { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() .setSbn(createNotification( SHORTCUT_ID, /* isMessagingStyle = */ false, /* isMissedCall = */ true)) - .setId(1)); + .setShortcutInfo(mShortcutInfo) + .setId(1); + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); mClock.advanceTime(MIN_LINGER_DURATION); verify(mAppWidgetManager, times(1)) @@ -645,11 +670,15 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { throws Exception { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() .setSbn(createNotification( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) - .setId(1)); + .setShortcutInfo(mShortcutInfo) + .setId(1); + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); mClock.advanceTime(MIN_LINGER_DURATION); verify(mAppWidgetManager, times(1)) @@ -659,7 +688,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { PeopleSpaceTile tile = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tile.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); - assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT); + assertThat(tile.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); } @@ -670,11 +699,15 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() .setSbn(createNotification( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) - .setId(1)); + .setShortcutInfo(mShortcutInfo) + .setId(1); + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); mClock.advanceTime(MIN_LINGER_DURATION); verify(mAppWidgetManager, times(1)) @@ -684,7 +717,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( - NOTIFICATION_CONTENT); + NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); verify(mAppWidgetManager, times(1)) @@ -693,7 +726,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { Bundle bundleForSameUriTile = requireNonNull(mBundleArgumentCaptor.getValue()); PeopleSpaceTile tileWithSameUri = bundleForSameUriTile.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tileWithSameUri.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); - assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT); + assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), any()); } @@ -704,12 +737,19 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() .setSbn(createNotification( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) - .setId(1)); + .setShortcutInfo(mShortcutInfo) + .setId(1); + + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); mClock.advanceTime(MIN_LINGER_DURATION); + + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of()); NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn.cloneLight(), 0); mClock.advanceTime(MIN_LINGER_DURATION); @@ -733,45 +773,11 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { } @Test - public void testDoNotRemoveMissedCallIfMatchingUriTileMissingReadContactsPermissionWhenPosted() - throws Exception { - when(mPackageManager.checkPermission(any(), - eq(PERSON_TILE_WITH_SAME_URI.getPackageName()))).thenReturn( - PERMISSION_HARD_DENIED); - int[] widgetIdsArray = - {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; - when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() - .setSbn(createNotification( - SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) - .setId(1)); - mClock.advanceTime(MIN_LINGER_DURATION); - // We should only try to remove the notification if the Missed Call was added when posted. - NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn.cloneLight(), 0); - mClock.advanceTime(MIN_LINGER_DURATION); - - verify(mAppWidgetManager, times(2)).updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), - mBundleArgumentCaptor.capture()); - Bundle bundle = mBundleArgumentCaptor.getValue(); - PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE); - assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(null); - assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo(null); - verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), - any()); - verify(mAppWidgetManager, times(0)) - .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SAME_URI), any()); - verify(mAppWidgetManager, times(0)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), - any()); - } - - @Test public void testUpdateMissedCallNotificationWithContentPostedIfMatchingUriTileFromSender() throws Exception { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - Notification notificationWithPersonOnlyInSender = createMessagingStyleNotificationWithoutExtras( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ @@ -782,9 +788,15 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .setUid(0) .setUser(new UserHandle(0)) .build(); - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() + .setRank(1) + .setShortcutInfo(mShortcutInfo) .setSbn(sbn) - .setId(1)); + .setId(1); + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); mClock.advanceTime(MIN_LINGER_DURATION); verify(mAppWidgetManager, times(1)) @@ -794,7 +806,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( - NOTIFICATION_CONTENT); + NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); verify(mAppWidgetManager, times(1)) @@ -803,7 +815,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { Bundle bundleForSameUriTile = requireNonNull(mBundleArgumentCaptor.getValue()); PeopleSpaceTile tileWithSameUri = bundleForSameUriTile.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tileWithSameUri.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); - assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT); + assertThat(tileWithSameUri.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), any()); } @@ -814,14 +826,13 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - // Notification posted without any Person attached. Notification notificationWithoutPersonObject = createMessagingStyleNotificationWithoutExtras( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true).setStyle(new Notification.MessagingStyle("sender") .addMessage( - new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT, 10, + new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT_1, 10, "sender")) ).build(); StatusBarNotification sbn = new SbnBuilder() @@ -830,9 +841,15 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .setUid(0) .setUser(new UserHandle(0)) .build(); - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() .setSbn(sbn) - .setId(1)); + .setShortcutInfo(mShortcutInfo) + .setId(1); + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); + mClock.advanceTime(MIN_LINGER_DURATION); verify(mAppWidgetManager, times(1)) @@ -842,7 +859,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( - NOTIFICATION_CONTENT); + NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); // Do not update since notification doesn't include a Person reference. @@ -863,11 +880,15 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_DIFFERENT_URI}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() .setSbn(createNotification( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) - .setId(1)); + .setShortcutInfo(mShortcutInfo) + .setId(1); + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); mClock.advanceTime(MIN_LINGER_DURATION); verify(mAppWidgetManager, times(1)) @@ -877,7 +898,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( - NOTIFICATION_CONTENT); + NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); // Do not update since missing permission to read contacts. @@ -897,11 +918,15 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT, WIDGET_ID_WITH_SAME_URI}; when(mAppWidgetManager.getAppWidgetIds(any())).thenReturn(widgetIdsArray); - - NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + NotificationEntryBuilder builder = new NotificationEntryBuilder() .setSbn(createNotification( SHORTCUT_ID, /* isMessagingStyle = */ true, /* isMissedCall = */ true)) - .setId(1)); + .setShortcutInfo(mShortcutInfo) + .setId(1); + NotificationEntry entry = builder.build(); + when(mNotificationEntryManager.getVisibleNotifications()).thenReturn(List.of(entry)); + + NotifEvent notif1 = mNoMan.postNotif(builder); mClock.advanceTime(MIN_LINGER_DURATION); verify(mAppWidgetManager, times(1)) @@ -911,14 +936,18 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { PeopleSpaceTile tileWithMissedCallOrigin = bundle.getParcelable(OPTIONS_PEOPLE_TILE); assertThat(tileWithMissedCallOrigin.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(tileWithMissedCallOrigin.getNotificationContent()).isEqualTo( - NOTIFICATION_CONTENT); + NOTIFICATION_CONTENT_1); verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); // Do not update since missing permission to read contacts. - verify(mAppWidgetManager, times(0)) + verify(mAppWidgetManager, times(1)) .updateAppWidgetOptions(eq(WIDGET_ID_WITH_SAME_URI), - any()); - verify(mAppWidgetManager, times(0)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), + mBundleArgumentCaptor.capture()); + Bundle noNotificationBundle = requireNonNull(mBundleArgumentCaptor.getValue()); + PeopleSpaceTile tileNoNotification = + noNotificationBundle.getParcelable(OPTIONS_PEOPLE_TILE); + assertThat(tileNoNotification.getNotificationKey()).isNull(); + verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SAME_URI), any()); } @@ -952,7 +981,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { public void testAddThenReconfigureWidgetsUpdatesStorageCacheAndListeners() throws Exception { clearStorage(); - mManager.addNewWidget(WIDGET_ID_WITH_SHORTCUT, PERSON_TILE); + mManager.addNewWidget(WIDGET_ID_WITH_SHORTCUT, new PeopleTileKey(PERSON_TILE)); // Check storage. SharedPreferences widgetSp = mContext.getSharedPreferences( String.valueOf(WIDGET_ID_WITH_SHORTCUT), @@ -971,7 +1000,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { eq(LauncherApps.FLAG_CACHE_PEOPLE_TILE_SHORTCUTS)); // Reconfigure WIDGET_ID_WITH_SHORTCUT from PERSON_TILE to PERSON_TILE_WITH_SAME_URI - mManager.addNewWidget(WIDGET_ID_WITH_SHORTCUT, PERSON_TILE_WITH_SAME_URI); + mManager.addNewWidget( + WIDGET_ID_WITH_SHORTCUT, new PeopleTileKey(PERSON_TILE_WITH_SAME_URI)); // Check listener is removed and shortcut is uncached. verify(mPeopleManager).unregisterConversationListener(any()); @@ -1120,26 +1150,28 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @Test public void testGetPeopleTileFromPersistentStorageExistingConversation() throws Exception { - when(mIPeopleManager.getConversation(PACKAGE_NAME, 0, SHORTCUT_ID)).thenReturn( - getConversationWithShortcutId(SHORTCUT_ID)); - PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, PACKAGE_NAME); + ConversationChannel channel = getConversationWithShortcutId( + new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A)); + when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(channel); + PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key); assertThat(tile.getId()).isEqualTo(key.getShortcutId()); } @Test - public void testGetPeopleTileFromPersistentStorageNoConversation() { - PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, PACKAGE_NAME); + public void testGetPeopleTileFromPersistentStorageNoConversation() throws RemoteException { + when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null); + PeopleTileKey key = new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A); PeopleSpaceTile tile = mManager.getTileFromPersistentStorage(key); assertThat(tile).isNull(); } @Test public void testRequestPinAppWidgetExistingConversation() throws Exception { - when(mMockContext.getPackageName()).thenReturn(PACKAGE_NAME); - when(mMockContext.getUserId()).thenReturn(0); - when(mIPeopleManager.getConversation(PACKAGE_NAME, 0, SHORTCUT_ID)) - .thenReturn(getConversationWithShortcutId(SHORTCUT_ID)); + ConversationChannel channel = getConversationWithShortcutId( + new PeopleTileKey(SHORTCUT_ID, 0, TEST_PACKAGE_A)); + when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)) + .thenReturn(channel); when(mAppWidgetManager.requestPinAppWidget(any(), any(), any())).thenReturn(true); ShortcutInfo info = new ShortcutInfo.Builder(mMockContext, SHORTCUT_ID).build(); @@ -1152,9 +1184,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @Test public void testRequestPinAppWidgetNoConversation() throws Exception { - when(mMockContext.getPackageName()).thenReturn(PACKAGE_NAME); - when(mMockContext.getUserId()).thenReturn(0); - when(mIPeopleManager.getConversation(PACKAGE_NAME, 0, SHORTCUT_ID)).thenReturn(null); + when(mIPeopleManager.getConversation(TEST_PACKAGE_A, 0, SHORTCUT_ID)).thenReturn(null); ShortcutInfo info = new ShortcutInfo.Builder(mMockContext, SHORTCUT_ID).build(); boolean valid = mManager.requestPinAppWidget(info, new Bundle()); @@ -1163,6 +1193,57 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { verify(mAppWidgetManager, never()).requestPinAppWidget(any(), any(), any()); } + @Test + public void testAugmentTileFromNotifications() { + PeopleSpaceTile tile = + new PeopleSpaceTile + .Builder(SHORTCUT_ID, "userName", ICON, new Intent()) + .setPackageName(TEST_PACKAGE_A) + .setUserHandle(new UserHandle(0)) + .build(); + PeopleSpaceTile actual = mManager.augmentTileFromNotifications(tile, EMPTY_STRING, + Map.of(new PeopleTileKey(mNotificationEntry), + new HashSet<>(Collections.singleton(mNotificationEntry)))); + + assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_CONTENT_1); + } + + @Test + public void testAugmentTileFromNotificationsDifferentShortcutId() { + PeopleSpaceTile tile = + new PeopleSpaceTile + .Builder(OTHER_SHORTCUT_ID, "userName", ICON, new Intent()) + .setPackageName(TEST_PACKAGE_A) + .setUserHandle(new UserHandle(0)) + .build(); + PeopleSpaceTile actual = mManager + .augmentTileFromNotifications(tile, EMPTY_STRING, + Map.of(new PeopleTileKey(mNotificationEntry), + new HashSet<>(Collections.singleton(mNotificationEntry)))); + + assertThat(actual.getNotificationContent()).isEqualTo(null); + } + + @Test + public void testAugmentTileFromNotificationEntryManager() { + PeopleSpaceTile tile = + new PeopleSpaceTile + .Builder(SHORTCUT_ID, "userName", ICON, new Intent()) + .setPackageName(TEST_PACKAGE_A) + .setUserHandle(new UserHandle(0)) + .build(); + when(mNotificationEntryManager.getVisibleNotifications()) + .thenReturn(List.of(mNotificationEntry)); + + PeopleSpaceTile actual = + mManager.augmentTileFromNotificationEntryManager(tile); + + assertThat(actual.getNotificationContent().toString()).isEqualTo(NOTIFICATION_CONTENT_1); + + verify(mNotificationEntryManager, times(1)) + .getVisibleNotifications(); + } + /** * Adds another widget for {@code PERSON_TILE} with widget ID: {@code * SECOND_WIDGET_ID_WITH_SHORTCUT}. @@ -1179,10 +1260,11 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { setStorageForTile(tile.getId(), tile.getPackageName(), widgetId, tile.getContactUri()); Bundle options = new Bundle(); options.putParcelable(OPTIONS_PEOPLE_TILE, tile); + ConversationChannel channel = getConversationWithShortcutId(new PeopleTileKey(tile)); when(mAppWidgetManager.getAppWidgetOptions(eq(widgetId))) .thenReturn(options); - when(mIPeopleManager.getConversation(tile.getPackageName(), 0, tile.getId())).thenReturn( - getConversationWithShortcutId(tile.getId())); + when(mIPeopleManager.getConversation(tile.getPackageName(), 0, tile.getId())) + .thenReturn(channel); when(mPackageManager.checkPermission(any(), eq(tile.getPackageName()))).thenReturn( PERMISSION_GRANTED); } @@ -1190,17 +1272,19 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { /** * Returns a single conversation associated with {@code shortcutId}. */ - private ConversationChannel getConversationWithShortcutId(String shortcutId) throws Exception { - return getConversationWithShortcutId(shortcutId, Arrays.asList()); + private ConversationChannel getConversationWithShortcutId(PeopleTileKey key) throws Exception { + return getConversationWithShortcutId(key, Arrays.asList()); } /** * Returns a single conversation associated with {@code shortcutId} and {@code statuses}. */ - private ConversationChannel getConversationWithShortcutId(String shortcutId, + private ConversationChannel getConversationWithShortcutId(PeopleTileKey key, List<ConversationStatus> statuses) throws Exception { - ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel( - "name").setPerson(PERSON).build(); + when(mMockContext.getPackageName()).thenReturn(key.getPackageName()); + when(mMockContext.getUserId()).thenReturn(key.getUserId()); + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mMockContext, key.getShortcutId()) + .setLongLabel("name").setPerson(PERSON).build(); ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null, 0L, false, false, statuses); return convo; @@ -1220,7 +1304,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { if (isMessagingStyle) { builder.setStyle(new Notification.MessagingStyle(PERSON) .addMessage( - new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT, 10, + new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT_1, 10, PERSON)) ); } @@ -1239,7 +1323,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { if (isMessagingStyle) { builder.setStyle(new Notification.MessagingStyle(PERSON) .addMessage( - new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT, 10, + new Notification.MessagingStyle.Message(NOTIFICATION_CONTENT_1, 10, PERSON)) ); } |