Add birthdays to People Space tiles
Birthdays only appear if no notification content is currently present. They are removed as a status once no longer returned from the Contacts DB, meaning if removed from the Contacts DB or if queried the day after the birthday. Test: in-progress Change-Id: I35a6a5e5644de281220b7af7c2779e06f0233c47
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -169,14 +169,16 @@
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:background="@drawable/people_space_content_background"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<TextView
|
||||
android:id="@+id/content"
|
||||
android:paddingVertical="3dp"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
|
||||
android:textSize="14sp"
|
||||
android:textSize="16sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:maxLines="2"
|
||||
|
||||
@@ -2773,6 +2773,14 @@
|
||||
<string name="basic_status" translatable="false">Open conversation</string>
|
||||
<!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
|
||||
<string name="select_conversation_text" translatable="false">Select one conversation to show in your widget:</string>
|
||||
<!-- Timestamp for notification with exact time [CHAR LIMIT=120] -->
|
||||
<string name="timestamp" translatable="false"><xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
|
||||
<!-- Timestamp for notification when less than a certain time window [CHAR LIMIT=120] -->
|
||||
<string name="less_than_timestamp" translatable="false">Less than <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
|
||||
<!-- Timestamp for notification when over a certain time window [CHAR LIMIT=120] -->
|
||||
<string name="over_timestamp" translatable="false">Over <xliff:g id="duration" example="1 week">%1$s</xliff:g> ago</string>
|
||||
<!-- Status text for a birthday today [CHAR LIMIT=120] -->
|
||||
<string name="birthday_status" translatable="false">Today is their birthday!</string>
|
||||
|
||||
<!-- Title to display in a notification when ACTION_BATTERY_CHANGED.EXTRA_PRESENT field is false
|
||||
[CHAR LIMIT=NONE] -->
|
||||
|
||||
@@ -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<Map.Entry<Long, PeopleSpaceTile>> tiles = PeopleSpaceUtils.getTiles(
|
||||
List<PeopleSpaceTile> tiles = PeopleSpaceUtils.getTiles(
|
||||
mContext, mNotificationManager, mPeopleManager, mLauncherApps);
|
||||
for (Map.Entry<Long, PeopleSpaceTile> 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());
|
||||
|
||||
@@ -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<Map.Entry<Long, PeopleSpaceTile>> getTiles(
|
||||
public static List<PeopleSpaceTile> 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<ConversationChannelWrapper> conversations = notificationManager.getConversations(
|
||||
true).getList();
|
||||
List<Map.Entry<Long, PeopleSpaceTile>> tiles = getSortedTiles(peopleManager,
|
||||
conversations.stream().map(c ->
|
||||
new PeopleSpaceTile.Builder(c.getShortcutInfo(), launcherApps).build()));
|
||||
List<PeopleSpaceTile> 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<ConversationChannel> recentConversations =
|
||||
peopleManager.getRecentConversations().getList();
|
||||
List<Map.Entry<Long, PeopleSpaceTile>> recentTiles =
|
||||
getSortedTiles(peopleManager, recentConversations.stream().map(c ->
|
||||
new PeopleSpaceTile
|
||||
.Builder(c.getShortcutInfo(), launcherApps)
|
||||
.build()));
|
||||
List<PeopleSpaceTile> 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<Integer, PeopleSpaceTile> widgetIdToTile = new HashMap<>();
|
||||
try {
|
||||
List<Map.Entry<Long, PeopleSpaceTile>> tiles =
|
||||
List<PeopleSpaceTile> 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<Map.Entry<Long, PeopleSpaceTile>> entry = tiles.stream().filter(
|
||||
e -> e.getValue().getId().equals(shortcutId)).findFirst();
|
||||
|
||||
Optional<PeopleSpaceTile> 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<Map.Entry<Long, PeopleSpaceTile>> getSortedTiles(
|
||||
IPeopleManager peopleManager, Stream<PeopleSpaceTile> 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<PeopleSpaceTile> getSortedTiles(IPeopleManager peopleManager,
|
||||
Stream<PeopleSpaceTile> 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<Integer, PeopleSpaceTile> 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<Integer, PeopleSpaceTile> widgetIdToTile, int[] appWidgetIds) {
|
||||
if (DEBUG) Log.d(TAG, "Get birthdays");
|
||||
if (appWidgetIds.length == 0) return;
|
||||
List<String> 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<String> 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.
|
||||
*
|
||||
* <p>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<String> getContactLookupKeysWithBirthdaysToday(Context context) {
|
||||
List<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Map.Entry<Long, PeopleSpaceTile>> mTiles = new ArrayList<>();
|
||||
private List<PeopleSpaceTile> 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<Long, PeopleSpaceTile> 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());
|
||||
|
||||
@@ -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<Integer, PeopleSpaceTile> 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<Integer, PeopleSpaceTile> 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<Integer, PeopleSpaceTile> 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<Integer, PeopleSpaceTile> 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<NotificationHandler> 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()
|
||||
|
||||
Reference in New Issue
Block a user