diff --git a/core/java/android/app/people/PeopleSpaceTile.java b/core/java/android/app/people/PeopleSpaceTile.java index f60e42f6bfab0..95739f3dbf916 100644 --- a/core/java/android/app/people/PeopleSpaceTile.java +++ b/core/java/android/app/people/PeopleSpaceTile.java @@ -17,6 +17,7 @@ package android.app.people; import android.annotation.NonNull; +import android.app.Person; import android.content.Intent; import android.content.pm.LauncherApps; import android.content.pm.ShortcutInfo; @@ -44,6 +45,7 @@ public class PeopleSpaceTile implements Parcelable { private int mUid; private Uri mContactUri; private String mPackageName; + private String mStatusText; private long mLastInteractionTimestamp; private boolean mIsImportantConversation; private boolean mIsHiddenConversation; @@ -61,6 +63,7 @@ public class PeopleSpaceTile implements Parcelable { mContactUri = b.mContactUri; mUid = b.mUid; mPackageName = b.mPackageName; + mStatusText = b.mStatusText; mLastInteractionTimestamp = b.mLastInteractionTimestamp; mIsImportantConversation = b.mIsImportantConversation; mIsHiddenConversation = b.mIsHiddenConversation; @@ -95,6 +98,10 @@ public class PeopleSpaceTile implements Parcelable { return mPackageName; } + public String getStatusText() { + return mStatusText; + } + /** Returns the timestamp of the last interaction. */ public long getLastInteractionTimestamp() { return mLastInteractionTimestamp; @@ -148,6 +155,7 @@ public class PeopleSpaceTile implements Parcelable { builder.setContactUri(mContactUri); builder.setUid(mUid); builder.setPackageName(mPackageName); + builder.setStatusText(mStatusText); builder.setLastInteractionTimestamp(mLastInteractionTimestamp); builder.setIsImportantConversation(mIsImportantConversation); builder.setIsHiddenConversation(mIsHiddenConversation); @@ -165,6 +173,7 @@ public class PeopleSpaceTile implements Parcelable { private Uri mContactUri; private int mUid; private String mPackageName; + private String mStatusText; private long mLastInteractionTimestamp; private boolean mIsImportantConversation; private boolean mIsHiddenConversation; @@ -188,6 +197,16 @@ public class PeopleSpaceTile implements Parcelable { mUserIcon = convertDrawableToIcon(launcherApps.getShortcutIconDrawable(info, 0)); mUid = info.getUserId(); mPackageName = info.getPackage(); + mContactUri = getContactUri(info); + } + + private Uri getContactUri(ShortcutInfo info) { + if (info.getPersons() == null || info.getPersons().length != 1) { + return null; + } + // TODO(b/175584929): Update to use the Uri from PeopleService directly + Person person = info.getPersons()[0]; + return person.getUri() == null ? null : Uri.parse(person.getUri()); } /** Sets the ID for the tile. */ @@ -226,6 +245,12 @@ public class PeopleSpaceTile implements Parcelable { return this; } + /** Sets the status text. */ + public Builder setStatusText(String statusText) { + mStatusText = statusText; + return this; + } + /** Sets the last interaction timestamp. */ public Builder setLastInteractionTimestamp(long lastInteractionTimestamp) { mLastInteractionTimestamp = lastInteractionTimestamp; @@ -279,8 +304,10 @@ public class PeopleSpaceTile implements Parcelable { mId = in.readString(); mUserName = in.readCharSequence(); mUserIcon = in.readParcelable(Icon.class.getClassLoader()); + mContactUri = in.readParcelable(Uri.class.getClassLoader()); mUid = in.readInt(); mPackageName = in.readString(); + mStatusText = in.readString(); mLastInteractionTimestamp = in.readLong(); mIsImportantConversation = in.readBoolean(); mIsHiddenConversation = in.readBoolean(); @@ -300,8 +327,10 @@ public class PeopleSpaceTile implements Parcelable { dest.writeString(mId); dest.writeCharSequence(mUserName); dest.writeParcelable(mUserIcon, flags); + dest.writeParcelable(mContactUri, flags); dest.writeInt(mUid); dest.writeString(mPackageName); + dest.writeString(mStatusText); dest.writeLong(mLastInteractionTimestamp); dest.writeBoolean(mIsImportantConversation); dest.writeBoolean(mIsHiddenConversation); diff --git a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml index b715999b477c9..5aa05334539b2 100644 --- a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml +++ b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml @@ -169,14 +169,16 @@ Open conversation Select one conversation to show in your widget: + + %1$s ago + + Less than %1$s ago + + Over %1$s ago + + Today is their birthday! diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java index 62de9398b4618..2ad12b9afdde5 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java @@ -44,7 +44,6 @@ import com.android.systemui.R; import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; import java.util.List; -import java.util.Map; /** * Shows the user their tiles for their priority People (go/live-status). @@ -96,13 +95,12 @@ public class PeopleSpaceActivity extends Activity { */ private void setTileViewsWithPriorityConversations() { try { - List> tiles = PeopleSpaceUtils.getTiles( + List tiles = PeopleSpaceUtils.getTiles( mContext, mNotificationManager, mPeopleManager, mLauncherApps); - for (Map.Entry entry : tiles) { - PeopleSpaceTile tile = entry.getValue(); + for (PeopleSpaceTile tile : tiles) { PeopleSpaceTileView tileView = new PeopleSpaceTileView(mContext, mPeopleSpaceLayout, tile.getId()); - setTileView(tileView, tile, entry.getKey()); + setTileView(tileView, tile); } } catch (Exception e) { Log.e(TAG, "Couldn't retrieve conversations", e); @@ -110,12 +108,12 @@ public class PeopleSpaceActivity extends Activity { } /** Sets {@code tileView} with the data in {@code conversation}. */ - private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile, - long lastInteraction) { + private void setTileView(PeopleSpaceTileView tileView, PeopleSpaceTile tile) { try { String pkg = tile.getPackageName(); String status = - PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction); + PeopleSpaceUtils.getLastInteractionString(mContext, + tile.getLastInteractionTimestamp(), true); tileView.setStatus(status); tileView.setName(tile.getUserName().toString()); diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index 2cfbd3facea68..f1a57bf4e2e77 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -29,6 +29,8 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.LauncherApps; +import android.database.Cursor; +import android.database.SQLException; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; @@ -41,7 +43,7 @@ import android.os.Bundle; import android.os.Parcelable; import android.os.ServiceManager; import android.os.UserHandle; -import android.preference.PreferenceManager; +import android.provider.ContactsContract; import android.provider.Settings; import android.service.notification.ConversationChannelWrapper; import android.service.notification.StatusBarNotification; @@ -49,17 +51,24 @@ import android.util.Log; import android.view.View; import android.widget.RemoteViews; +import androidx.preference.PreferenceManager; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; import com.android.internal.util.ArrayUtils; +import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.R; import com.android.systemui.people.widget.LaunchConversationActivity; import com.android.systemui.people.widget.PeopleSpaceWidgetProvider; +import java.text.SimpleDateFormat; import java.time.Duration; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -114,7 +123,7 @@ public class PeopleSpaceUtils { } /** Returns a list of map entries corresponding to user's conversations. */ - public static List> getTiles( + public static List getTiles( Context context, INotificationManager notificationManager, IPeopleManager peopleManager, LauncherApps launcherApps) throws Exception { @@ -122,70 +131,72 @@ public class PeopleSpaceUtils { Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 1; List conversations = notificationManager.getConversations( true).getList(); - List> tiles = getSortedTiles(peopleManager, - conversations.stream().map(c -> - new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build())); + List tiles = getSortedTiles(peopleManager, + conversations.stream().filter(c -> c.getShortcutInfo() != null).map( + c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(), + launcherApps).build())); if (!showOnlyPriority) { if (DEBUG) Log.d(TAG, "Add recent conversations"); List recentConversations = peopleManager.getRecentConversations().getList(); - List> recentTiles = - getSortedTiles(peopleManager, recentConversations.stream().map(c -> - new PeopleSpaceTile - .Builder(c.getShortcutInfo(), launcherApps) - .build())); + List recentTiles = + getSortedTiles(peopleManager, + recentConversations + .stream() + .filter( + c -> c.getShortcutInfo() != null) + .map( + c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(), + launcherApps).build())); tiles.addAll(recentTiles); } return tiles; } - /** Updates {@code appWidgetIds} with their associated conversation stored. */ + /** + * Updates {@code appWidgetIds} with their associated conversation stored, handling a + * notification being posted or removed. + */ public static void updateSingleConversationWidgets(Context context, int[] appWidgetIds, AppWidgetManager appWidgetManager, INotificationManager notificationManager) { IPeopleManager peopleManager = IPeopleManager.Stub.asInterface( ServiceManager.getService(Context.PEOPLE_SERVICE)); LauncherApps launcherApps = context.getSystemService(LauncherApps.class); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + Map widgetIdToTile = new HashMap<>(); try { - List> tiles = + List tiles = PeopleSpaceUtils.getTiles(context, notificationManager, peopleManager, launcherApps); - for (int appWidgetId : appWidgetIds) { String shortcutId = sp.getString(String.valueOf(appWidgetId), null); if (DEBUG) { - Log.d(TAG, "Set widget: " + appWidgetId + " with shortcut ID: " + shortcutId); + Log.d(TAG, "Widget ID: " + appWidgetId + " Shortcut ID: " + shortcutId); } - Optional> entry = tiles.stream().filter( - e -> e.getValue().getId().equals(shortcutId)).findFirst(); + + Optional entry = tiles.stream().filter( + e -> e.getId().equals(shortcutId)).findFirst(); + if (!entry.isPresent() || shortcutId == null) { if (DEBUG) Log.d(TAG, "Matching conversation not found for shortcut ID"); //TODO: Delete app widget id when crash is fixed (b/175486868) continue; } - PeopleSpaceTile tile = - augmentTileFromStorage(entry.get().getValue(), appWidgetManager, - appWidgetId); - - RemoteViews views = createRemoteViews(context, tile, entry.get().getKey(), + // Augment current tile based on stored fields. + PeopleSpaceTile tile = augmentTileFromStorage(entry.get(), appWidgetManager, appWidgetId); + RemoteViews views = createRemoteViews(context, tile, appWidgetId); + // Tell the AppWidgetManager to perform an update on the current app widget. appWidgetManager.updateAppWidget(appWidgetId, views); + + widgetIdToTile.put(appWidgetId, tile); } } catch (Exception e) { - Log.e(TAG, "Exception updating single conversation widgets: " + e); + Log.e(TAG, "Failed to retrieve conversations to set tiles: " + e); } - } - - /** Returns a list sorted by ascending last interaction time from {@code stream}. */ - private static List> getSortedTiles( - IPeopleManager peopleManager, Stream stream) { - return stream - .filter(c -> shouldKeepConversation(c)) - .map(c -> Map.entry(getLastInteraction(peopleManager, c), c)) - .sorted((c1, c2) -> (c2.getKey().compareTo(c1.getKey()))) - .collect(Collectors.toList()); + getBirthdaysOnBackgroundThread(context, appWidgetManager, widgetIdToTile, appWidgetIds); } /** Augment {@link PeopleSpaceTile} with fields from stored tile. */ @@ -198,6 +209,7 @@ public class PeopleSpaceUtils { return tile; } return tile.toBuilder() + .setStatusText(storedTile.getStatusText()) .setNotificationKey(storedTile.getNotificationKey()) .setNotificationContent(storedTile.getNotificationContent()) .setNotificationDataUri(storedTile.getNotificationDataUri()) @@ -234,37 +246,67 @@ public class PeopleSpaceUtils { .setNotificationDataUri(null) .build(); } + updateAppWidgetOptions(appWidgetManager, appWidgetId, storedTile); + } + + private static void updateAppWidgetOptions(AppWidgetManager appWidgetManager, int appWidgetId, + PeopleSpaceTile tile) { Bundle newOptions = new Bundle(); - newOptions.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, storedTile); + newOptions.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, tile); appWidgetManager.updateAppWidgetOptions(appWidgetId, newOptions); } - private static RemoteViews createRemoteViews(Context context, PeopleSpaceTile tile, - long lastInteraction, int appWidgetId) throws Exception { - // TODO: If key is null or if text and data uri are null. - if (tile.getNotificationKey() == null) { - return createLastInteractionRemoteViews(context, tile, lastInteraction, appWidgetId); + /** Creates a {@link RemoteViews} for {@code tile}. */ + private static RemoteViews createRemoteViews(Context context, + PeopleSpaceTile tile, int appWidgetId) { + RemoteViews views; + if (tile.getNotificationKey() != null) { + views = createNotificationRemoteViews(context, tile); + } else if (tile.getStatusText() != null) { + views = createStatusRemoteViews(context, tile); + } else { + views = createLastInteractionRemoteViews(context, tile); } - return createNotificationRemoteViews(context, tile, lastInteraction, appWidgetId); + return setCommonRemoteViewsFields(context, views, tile, appWidgetId); } - private static RemoteViews createLastInteractionRemoteViews(Context context, - PeopleSpaceTile tile, long lastInteraction, int appWidgetId) - throws Exception { - RemoteViews views = new RemoteViews( - context.getPackageName(), R.layout.people_space_large_avatar_tile); - String status = PeopleSpaceUtils.getLastInteractionString( - context, lastInteraction); - views.setTextViewText(R.id.status, status); + private static RemoteViews setCommonRemoteViewsFields(Context context, RemoteViews views, + PeopleSpaceTile tile, int appWidgetId) { + try { + views.setTextViewText(R.id.name, tile.getUserName().toString()); + views.setImageViewBitmap( + R.id.package_icon, + PeopleSpaceUtils.convertDrawableToBitmap( + context.getPackageManager().getApplicationIcon( + tile.getPackageName()) + ) + ); + views.setImageViewIcon(R.id.person_icon, tile.getUserIcon()); - views = setCommonRemoteViewsFields(context, views, tile, appWidgetId); - return views; + Intent activityIntent = new Intent(context, LaunchConversationActivity.class); + activityIntent.addFlags( + Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_NO_HISTORY + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId()); + activityIntent.putExtra( + PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName()); + activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid()); + views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity( + context, + appWidgetId, + activityIntent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE)); + return views; + } catch (Exception e) { + Log.e(TAG, "Failed to set common fields: " + e); + } + return null; } private static RemoteViews createNotificationRemoteViews(Context context, - PeopleSpaceTile tile, long lastInteraction, int appWidgetId) - throws Exception { - + PeopleSpaceTile tile) { RemoteViews views = new RemoteViews( context.getPackageName(), R.layout.people_space_small_avatar_tile); Uri image = tile.getNotificationDataUri(); @@ -280,38 +322,26 @@ public class PeopleSpaceUtils { views.setViewVisibility(R.id.content, View.VISIBLE); views.setViewVisibility(R.id.image, View.GONE); } - - views = setCommonRemoteViewsFields(context, views, tile, appWidgetId); + views.setTextViewText(R.id.time, PeopleSpaceUtils.getLastInteractionString( + context, tile.getLastInteractionTimestamp(), false)); return views; } - private static RemoteViews setCommonRemoteViewsFields( - Context context, RemoteViews views, PeopleSpaceTile tile, int appWidgetId) - throws Exception { - views.setTextViewText(R.id.name, tile.getUserName().toString()); - views.setImageViewBitmap( - R.id.package_icon, - PeopleSpaceUtils.convertDrawableToBitmap( - context.getPackageManager().getApplicationIcon(tile.getPackageName()) - ) - ); - views.setImageViewIcon(R.id.person_icon, tile.getUserIcon()); + private static RemoteViews createStatusRemoteViews(Context context, + PeopleSpaceTile tile) { + RemoteViews views = new RemoteViews( + context.getPackageName(), R.layout.people_space_large_avatar_tile); + views.setTextViewText(R.id.status, tile.getStatusText()); + return views; + } - Intent activityIntent = new Intent(context, LaunchConversationActivity.class); - activityIntent.addFlags( - Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_CLEAR_TASK - | Intent.FLAG_ACTIVITY_NO_HISTORY - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_TILE_ID, tile.getId()); - activityIntent.putExtra( - PeopleSpaceWidgetProvider.EXTRA_PACKAGE_NAME, tile.getPackageName()); - activityIntent.putExtra(PeopleSpaceWidgetProvider.EXTRA_UID, tile.getUid()); - views.setOnClickPendingIntent(R.id.item, PendingIntent.getActivity( - context, - appWidgetId, - activityIntent, - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE)); + private static RemoteViews createLastInteractionRemoteViews(Context context, + PeopleSpaceTile tile) { + RemoteViews views = new RemoteViews( + context.getPackageName(), R.layout.people_space_large_avatar_tile); + String status = PeopleSpaceUtils.getLastInteractionString( + context, tile.getLastInteractionTimestamp(), true); + views.setTextViewText(R.id.status, status); return views; } @@ -319,7 +349,7 @@ public class PeopleSpaceUtils { RemoteViews views, CharSequence content) { String punctuation = getBackgroundTextFromMessage(content.toString()); int visibility = View.GONE; - if (punctuation != null) { + if (punctuation != null) { visibility = View.VISIBLE; } views.setTextViewText(R.id.punctuation1, punctuation); @@ -364,6 +394,7 @@ public class PeopleSpaceUtils { } /** Gets the most recent {@link Notification.MessagingStyle.Message} from the notification. */ + @VisibleForTesting public static Notification.MessagingStyle.Message getLastMessagingStyleMessage( StatusBarNotification sbn) { Notification notification = sbn.getNotification(); @@ -384,6 +415,18 @@ public class PeopleSpaceUtils { return null; } + /** Returns a list sorted by ascending last interaction time from {@code stream}. */ + private static List getSortedTiles(IPeopleManager peopleManager, + Stream stream) { + return stream + .filter(c -> shouldKeepConversation(c)) + .map(c -> c.toBuilder().setLastInteractionTimestamp( + getLastInteraction(peopleManager, c)).build()) + .sorted((c1, c2) -> new Long(c2.getLastInteractionTimestamp()).compareTo( + new Long(c1.getLastInteractionTimestamp()))) + .collect(Collectors.toList()); + } + /** Returns the last interaction time with the user specified by {@code PeopleSpaceTile}. */ private static Long getLastInteraction(IPeopleManager peopleManager, PeopleSpaceTile tile) { @@ -426,7 +469,8 @@ public class PeopleSpaceUtils { } /** Returns a readable status describing the {@code lastInteraction}. */ - public static String getLastInteractionString(Context context, long lastInteraction) { + public static String getLastInteractionString(Context context, long lastInteraction, + boolean includeLastChatted) { if (lastInteraction == 0L) { Log.e(TAG, "Could not get valid last interaction"); return context.getString(R.string.basic_status); @@ -436,18 +480,25 @@ public class PeopleSpaceUtils { MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE); if (durationSinceLastInteraction.toHours() < MIN_HOUR) { - return context.getString(R.string.last_interaction_status_less_than, + return context.getString(includeLastChatted ? R.string.last_interaction_status_less_than + : R.string.less_than_timestamp, formatter.formatMeasures(new Measure(MIN_HOUR, MeasureUnit.HOUR))); } else if (durationSinceLastInteraction.toDays() < ONE_DAY) { - return context.getString(R.string.last_interaction_status, formatter.formatMeasures( - new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR))); + return context.getString( + includeLastChatted ? R.string.last_interaction_status : R.string.timestamp, + formatter.formatMeasures( + new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR))); } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) { - return context.getString(R.string.last_interaction_status, formatter.formatMeasures( - new Measure(durationSinceLastInteraction.toDays(), MeasureUnit.DAY))); + return context.getString( + includeLastChatted ? R.string.last_interaction_status : R.string.timestamp, + formatter.formatMeasures( + new Measure(durationSinceLastInteraction.toDays(), MeasureUnit.DAY))); } else { return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK - ? R.string.last_interaction_status : - R.string.last_interaction_status_over, + ? (includeLastChatted ? R.string.last_interaction_status : + R.string.timestamp) : + (includeLastChatted ? R.string.last_interaction_status_over + : R.string.over_timestamp), formatter.formatMeasures( new Measure(durationSinceLastInteraction.toDays() / DAYS_IN_A_WEEK, MeasureUnit.WEEK))); @@ -468,4 +519,139 @@ public class PeopleSpaceUtils { return tile != null && tile.getUserName().length() != 0; } + private static boolean hasBirthdayStatus(PeopleSpaceTile tile, Context context) { + return tile.getStatusText() != null && tile.getStatusText().equals( + context.getString(R.string.birthday_status)); + } + + + /** Calls to retrieve birthdays on a background thread. */ + private static void getBirthdaysOnBackgroundThread(Context context, + AppWidgetManager appWidgetManager, + Map peopleSpaceTiles, int[] appWidgetIds) { + ThreadUtils.postOnBackgroundThread( + () -> getBirthdays(context, appWidgetManager, peopleSpaceTiles, appWidgetIds)); + } + + /** Queries the Contacts DB for any birthdays today. */ + @VisibleForTesting + public static void getBirthdays(Context context, AppWidgetManager appWidgetManager, + Map widgetIdToTile, int[] appWidgetIds) { + if (DEBUG) Log.d(TAG, "Get birthdays"); + if (appWidgetIds.length == 0) return; + List lookupKeysWithBirthdaysToday = getContactLookupKeysWithBirthdaysToday(context); + for (int appWidgetId : appWidgetIds) { + PeopleSpaceTile storedTile = widgetIdToTile.get(appWidgetId); + if (storedTile == null || storedTile.getContactUri() == null) { + if (DEBUG) Log.d(TAG, "No contact uri for: " + storedTile); + removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId); + continue; + } + if (lookupKeysWithBirthdaysToday.isEmpty()) { + if (DEBUG) Log.d(TAG, "No birthdays today"); + removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId); + continue; + } + updateTileWithBirthday(context, appWidgetManager, lookupKeysWithBirthdaysToday, + storedTile, + appWidgetId); + } + } + + /** Removes the birthday status if present in {@code storedTile} and pushes the update. */ + private static void removeBirthdayStatusIfPresent(AppWidgetManager appWidgetManager, + Context context, PeopleSpaceTile storedTile, int appWidgetId) { + if (hasBirthdayStatus(storedTile, context)) { + if (DEBUG) Log.d(TAG, "Remove " + storedTile.getUserName() + "'s birthday"); + updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, + storedTile.toBuilder() + .setStatusText(null) + .build()); + } + } + + /** + * Update {@code storedTile} if the contact has a lookup key matched to any {@code + * lookupKeysWithBirthdays}. + */ + private static void updateTileWithBirthday(Context context, AppWidgetManager appWidgetManager, + List lookupKeysWithBirthdaysToday, PeopleSpaceTile storedTile, + int appWidgetId) { + Cursor cursor = null; + try { + cursor = context.getContentResolver().query(storedTile.getContactUri(), + null, null, null, null); + while (cursor != null && cursor.moveToNext()) { + String storedLookupKey = cursor.getString( + cursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)); + if (!storedLookupKey.isEmpty() && lookupKeysWithBirthdaysToday.contains( + storedLookupKey)) { + if (DEBUG) Log.d(TAG, storedTile.getUserName() + "'s birthday today!"); + updateAppWidgetOptionsAndView(appWidgetManager, context, appWidgetId, + storedTile.toBuilder() + .setStatusText(context.getString(R.string.birthday_status)) + .build()); + return; + } + } + } catch (SQLException e) { + Log.e(TAG, "Failed to query contact: " + e); + } finally { + if (cursor != null) { + cursor.close(); + } + } + removeBirthdayStatusIfPresent(appWidgetManager, context, storedTile, appWidgetId); + } + + /** Update app widget options and the current view. */ + private static void updateAppWidgetOptionsAndView(AppWidgetManager appWidgetManager, + Context context, int appWidgetId, PeopleSpaceTile tile) { + updateAppWidgetOptions(appWidgetManager, appWidgetId, tile); + RemoteViews views = createRemoteViews(context, + tile, appWidgetId); + appWidgetManager.updateAppWidget(appWidgetId, views); + } + + /** + * Returns lookup keys for all contacts with a birthday today. + * + *

Birthdays are queried from a different table within the Contacts DB than the table for + * the Contact Uri provided by most messaging apps. Matching by the contact ID is then quite + * fragile as the row IDs across the different tables are not guaranteed to stay aligned, so we + * match the data by {@link ContactsContract.ContactsColumns#LOOKUP_KEY} key to ensure proper + * matching across all the Contacts DB tables. + */ + private static List getContactLookupKeysWithBirthdaysToday(Context context) { + List lookupKeysWithBirthdaysToday = new ArrayList<>(1); + String today = new SimpleDateFormat("MM-dd").format(new Date()); + String[] projection = new String[]{ + ContactsContract.CommonDataKinds.Event.LOOKUP_KEY, + ContactsContract.CommonDataKinds.Event.START_DATE}; + String where = + ContactsContract.Data.MIMETYPE + + "= ? AND " + ContactsContract.CommonDataKinds.Event.TYPE + "=" + + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY + " AND substr(" + + ContactsContract.CommonDataKinds.Event.START_DATE + ",6) = ?"; + String[] selection = + new String[]{ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, today}; + Cursor cursor = null; + try { + cursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, + projection, where, selection, null); + while (cursor != null && cursor.moveToNext()) { + String lookupKey = cursor.getString( + cursor.getColumnIndex(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY)); + lookupKeysWithBirthdaysToday.add(lookupKey); + } + } catch (SQLException e) { + Log.e(TAG, "Failed to query birthdays: " + e); + } finally { + if (cursor != null) { + cursor.close(); + } + } + return lookupKeysWithBirthdaysToday; + } } + diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java index 1e6c213db852a..fb33affcbac5e 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetRemoteViewsFactory.java @@ -34,7 +34,6 @@ import com.android.systemui.people.PeopleSpaceUtils; import java.util.ArrayList; import java.util.List; -import java.util.Map; /** People Space Widget RemoteViewsFactory class. */ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { @@ -45,7 +44,7 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R private INotificationManager mNotificationManager; private PackageManager mPackageManager; private LauncherApps mLauncherApps; - private List> mTiles = new ArrayList<>(); + private List mTiles = new ArrayList<>(); private Context mContext; public PeopleSpaceWidgetRemoteViewsFactory(Context context, Intent intent) { @@ -100,11 +99,10 @@ public class PeopleSpaceWidgetRemoteViewsFactory implements RemoteViewsService.R RemoteViews personView = new RemoteViews(mContext.getPackageName(), R.layout.people_space_widget_item); try { - Map.Entry entry = mTiles.get(i); - PeopleSpaceTile tile = entry.getValue(); - long lastInteraction = entry.getKey(); + PeopleSpaceTile tile = mTiles.get(i); - String status = PeopleSpaceUtils.getLastInteractionString(mContext, lastInteraction); + String status = PeopleSpaceUtils.getLastInteractionString(mContext, + tile.getLastInteractionTimestamp(), true); personView.setTextViewText(R.id.status, status); personView.setTextViewText(R.id.name, tile.getUserName().toString()); 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 2a065af2a1fd8..644373c213afb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java @@ -21,7 +21,13 @@ import static com.android.systemui.people.PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; @@ -29,11 +35,16 @@ import android.app.Person; import android.app.people.PeopleSpaceTile; import android.appwidget.AppWidgetManager; import android.content.ContentResolver; +import android.content.Context; import android.content.Intent; +import android.content.pm.LauncherApps; +import android.content.pm.ShortcutInfo; +import android.database.Cursor; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; +import android.provider.ContactsContract; import android.provider.Settings; import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; @@ -52,6 +63,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Map; + @SmallTest @RunWith(AndroidTestingRunner.class) public class PeopleSpaceUtilsTest extends SysuiTestCase { @@ -61,6 +74,32 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { private static final String SHORTCUT_ID = "101"; private static final String NOTIFICATION_KEY = "notification_key"; private static final String NOTIFICATION_CONTENT = "notification_content"; + private static final String TEST_LOOKUP_KEY = "lookup_key"; + private static final int TEST_COLUMN_INDEX = 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 Person PERSON = new Person.Builder() + .setName("name") + .setKey("abc") + .setUri(URI.toString()) + .setBot(false) + .build(); + private static final PeopleSpaceTile PERSON_TILE = + new PeopleSpaceTile + .Builder(SHORTCUT_ID, "username", ICON, new Intent()) + .setNotificationKey(NOTIFICATION_KEY) + .setNotificationContent(NOTIFICATION_CONTENT) + .setNotificationDataUri(URI) + .build(); + + private final ShortcutInfo mShortcutInfo = new ShortcutInfo.Builder(mContext, + SHORTCUT_ID).setLongLabel( + "name").setPerson(PERSON) + .build(); + private final ShortcutInfo mShortcutInfoWithoutPerson = new ShortcutInfo.Builder(mContext, + SHORTCUT_ID).setLongLabel( + "name") + .build(); @Mock private NotificationListener mListenerService; @@ -68,26 +107,12 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { private IAppWidgetService mIAppWidgetService; @Mock private AppWidgetManager mAppWidgetManager; - - private static Icon sIcon = Icon.createWithResource("package", R.drawable.ic_android); - private static Uri sUri = new Uri.Builder() - .scheme(ContentResolver.SCHEME_CONTENT) - .authority("something") - .path("test") - .build(); - private static Person sPerson = new Person.Builder() - .setName("name") - .setKey("abc") - .setUri("uri") - .setBot(false) - .build(); - private static PeopleSpaceTile sPeopleSpaceTile = - new PeopleSpaceTile - .Builder(SHORTCUT_ID, "username", sIcon, new Intent()) - .setNotificationKey(NOTIFICATION_KEY) - .setNotificationContent(NOTIFICATION_CONTENT) - .setNotificationDataUri(sUri) - .build(); + @Mock + private Cursor mMockCursor; + @Mock + private ContentResolver mMockContentResolver; + @Mock + private Context mMockContext; @Before public void setUp() throws RemoteException { @@ -97,13 +122,19 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; Bundle options = new Bundle(); - options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, sPeopleSpaceTile); + options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE); when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT))) .thenReturn(options); when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT))) .thenReturn(new Bundle()); + + when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver); + when(mMockContentResolver.query(any(Uri.class), any(), anyString(), any(), + isNull())).thenReturn(mMockCursor); + when(mMockContext.getString(R.string.birthday_status)).thenReturn( + mContext.getString(R.string.birthday_status)); } @Test @@ -218,10 +249,10 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { .setContentTitle("TEST_TITLE") .setContentText("TEST_TEXT") .setShortcutId(SHORTCUT_ID) - .setStyle(new Notification.MessagingStyle(sPerson) - .addMessage(new Notification.MessagingStyle.Message("text1", 0, sPerson)) - .addMessage(new Notification.MessagingStyle.Message("text2", 20, sPerson)) - .addMessage(new Notification.MessagingStyle.Message("text3", 10, sPerson)) + .setStyle(new Notification.MessagingStyle(PERSON) + .addMessage(new Notification.MessagingStyle.Message("text1", 0, PERSON)) + .addMessage(new Notification.MessagingStyle.Message("text2", 20, PERSON)) + .addMessage(new Notification.MessagingStyle.Message("text3", 10, PERSON)) ) .build(); StatusBarNotification sbn = new SbnBuilder() @@ -238,21 +269,21 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { public void testAugmentTileFromStorageWithNotification() { PeopleSpaceTile tile = new PeopleSpaceTile - .Builder("id", "userName", sIcon, new Intent()) + .Builder("id", "userName", ICON, new Intent()) .build(); PeopleSpaceTile actual = PeopleSpaceUtils .augmentTileFromStorage(tile, mAppWidgetManager, WIDGET_ID_WITH_SHORTCUT); assertThat(actual.getNotificationKey()).isEqualTo(NOTIFICATION_KEY); assertThat(actual.getNotificationContent()).isEqualTo(NOTIFICATION_CONTENT); - assertThat(actual.getNotificationDataUri()).isEqualTo(sUri); + assertThat(actual.getNotificationDataUri()).isEqualTo(URI); } @Test public void testAugmentTileFromStorageWithoutNotification() { PeopleSpaceTile tile = new PeopleSpaceTile - .Builder("id", "userName", sIcon, new Intent()) + .Builder("id", "userName", ICON, new Intent()) .build(); PeopleSpaceTile actual = PeopleSpaceUtils .augmentTileFromStorage(tile, mAppWidgetManager, WIDGET_ID_WITHOUT_SHORTCUT); @@ -261,4 +292,98 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { assertThat(actual.getNotificationKey()).isEqualTo(null); assertThat(actual.getNotificationDataUri()).isEqualTo(null); } + + @Test + public void testDoNotUpdateSingleConversationAppWidgetWhenNotBirthday() { + int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; + when(mMockCursor.moveToNext()).thenReturn(true, false); + when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY); + when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY) + )).thenReturn(TEST_COLUMN_INDEX); + + // Existing tile does not have birthday status. + Map widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT, + new PeopleSpaceTile.Builder(mShortcutInfoWithoutPerson, + mContext.getSystemService(LauncherApps.class)).build()); + PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager, + widgetIdToTile, widgetIdsArray); + + verify(mAppWidgetManager, never()).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), + any()); + } + + @Test + public void testUpdateSingleConversationAppWidgetWithoutPersonContactUriToRemoveBirthday() { + int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; + when(mMockCursor.moveToNext()).thenReturn(true, false); + when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY); + when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY) + )).thenReturn(TEST_COLUMN_INDEX); + + // Existing tile has a birthday status. + Map widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT, + new PeopleSpaceTile.Builder(mShortcutInfoWithoutPerson, + mContext.getSystemService(LauncherApps.class)).setStatusText( + mContext.getString(R.string.birthday_status)).build()); + PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager, + widgetIdToTile, widgetIdsArray); + + verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), + any()); + } + + @Test + public void testUpdateSingleConversationAppWidgetToRemoveBirthdayWhenNoLongerBirthday() { + int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; + Cursor mockPersonUriCursor = mock(Cursor.class); + Cursor mockBirthdaysUriCursor = mock(Cursor.class); + when(mockPersonUriCursor.moveToNext()).thenReturn(true, false); + when(mockBirthdaysUriCursor.moveToNext()).thenReturn(true, false); + when(mockBirthdaysUriCursor.getColumnIndex( + eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY) + )).thenReturn(TEST_COLUMN_INDEX); + when(mockPersonUriCursor.getColumnIndex( + eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY) + )).thenReturn(TEST_COLUMN_INDEX); + // Return different cursors based on the Uri queried. + when(mMockContentResolver.query(eq(URI), any(), any(), any(), + any())).thenReturn(mockPersonUriCursor); + when(mMockContentResolver.query(eq(ContactsContract.Data.CONTENT_URI), any(), any(), any(), + any())).thenReturn(mockBirthdaysUriCursor); + // Each cursor returns a different lookup key. + when(mockBirthdaysUriCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY); + when(mockPersonUriCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn( + TEST_LOOKUP_KEY + "differentlookup"); + + // Existing tile has a birthday status. + Map widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT, + new PeopleSpaceTile.Builder(mShortcutInfo, + mContext.getSystemService(LauncherApps.class)).setStatusText( + mContext.getString(R.string.birthday_status)).build()); + PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager, + widgetIdToTile, widgetIdsArray); + + verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), + any()); + } + + @Test + public void testUpdateSingleConversationAppWidgetWhenBirthday() { + int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT}; + when(mMockCursor.moveToNext()).thenReturn(true, false, true, false); + when(mMockCursor.getString(eq(TEST_COLUMN_INDEX))).thenReturn(TEST_LOOKUP_KEY); + when(mMockCursor.getColumnIndex(eq(ContactsContract.CommonDataKinds.Event.LOOKUP_KEY) + )).thenReturn(TEST_COLUMN_INDEX); + + // Existing tile has a birthday status. + Map widgetIdToTile = Map.of(WIDGET_ID_WITH_SHORTCUT, + new PeopleSpaceTile.Builder(mShortcutInfo, + mContext.getSystemService(LauncherApps.class)).setStatusText( + mContext.getString(R.string.birthday_status)).build()); + PeopleSpaceUtils.getBirthdays(mMockContext, mAppWidgetManager, + widgetIdToTile, widgetIdsArray); + + verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), + any()); + } } 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 cd4f51ee9c924..df07b125e5fa0 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 @@ -37,7 +37,6 @@ import android.app.NotificationChannel; import android.app.Person; import android.app.people.PeopleSpaceTile; import android.appwidget.AppWidgetManager; -import android.content.ContentResolver; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ParceledListSlice; @@ -95,6 +94,21 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { private static final String OTHER_SHORTCUT_ID = "102"; private static final String NOTIFICATION_KEY = "notification_key"; private static final String NOTIFICATION_CONTENT = "notification_content"; + private static final Uri URI = Uri.parse("fake_uri"); + private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android); + private static final Person PERSON = new Person.Builder() + .setName("name") + .setKey("abc") + .setUri(URI.toString()) + .setBot(false) + .build(); + private static final PeopleSpaceTile PERSON_TILE = + new PeopleSpaceTile + .Builder(SHORTCUT_ID, "username", ICON, new Intent()) + .setNotificationKey(NOTIFICATION_KEY) + .setNotificationContent(NOTIFICATION_CONTENT) + .setNotificationDataUri(URI) + .build(); private PeopleSpaceWidgetManager mManager; @@ -110,26 +124,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { @Captor private ArgumentCaptor mListenerCaptor; - private static Icon sIcon = Icon.createWithResource("package", R.drawable.ic_android); - private static Uri sUri = new Uri.Builder() - .scheme(ContentResolver.SCHEME_CONTENT) - .authority("something") - .path("test") - .build(); - private static Person sPerson = new Person.Builder() - .setName("name") - .setKey("abc") - .setUri("uri") - .setBot(false) - .build(); - private static PeopleSpaceTile sPeopleSpaceTile = - new PeopleSpaceTile - .Builder(SHORTCUT_ID, "username", sIcon, new Intent()) - .setNotificationKey(NOTIFICATION_KEY) - .setNotificationContent(NOTIFICATION_CONTENT) - .setNotificationDataUri(sUri) - .build(); - private final NoManSimulator mNoMan = new NoManSimulator(); private final FakeSystemClock mClock = new FakeSystemClock(); @@ -150,9 +144,9 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); SharedPreferences.Editor editor = sp.edit(); editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID); - editor.commit(); + editor.apply(); Bundle options = new Bundle(); - options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, sPeopleSpaceTile); + options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, PERSON_TILE); when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT))) .thenReturn(options); @@ -304,7 +298,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH); mClock.advanceTime(MIN_LINGER_DURATION); - verify(mIAppWidgetService, never()).getAppWidgetIds(any()); verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt()); verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), any(RemoteViews.class)); @@ -456,8 +449,8 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { .setContentTitle("TEST_TITLE") .setContentText("TEST_TEXT") .setShortcutId(shortcutId) - .setStyle(new Notification.MessagingStyle(sPerson) - .addMessage(new Notification.MessagingStyle.Message("text3", 10, sPerson)) + .setStyle(new Notification.MessagingStyle(PERSON) + .addMessage(new Notification.MessagingStyle.Message("text3", 10, PERSON)) ) .build(); return new SbnBuilder()