Merge "Show notification content in single tile widget."

This commit is contained in:
Flavio Fiszman
2020-12-15 17:02:45 +00:00
committed by Android (Google) Code Review
8 changed files with 675 additions and 97 deletions

View File

@@ -28,7 +28,6 @@ import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.notification.StatusBarNotification;
/**
* The People Space tile contains all relevant information to render a tile in People Space: namely
@@ -48,7 +47,10 @@ public class PeopleSpaceTile implements Parcelable {
private long mLastInteractionTimestamp;
private boolean mIsImportantConversation;
private boolean mIsHiddenConversation;
private StatusBarNotification mNotification;
private String mNotificationKey;
// TODO: add mNotificationTimestamp
private CharSequence mNotificationContent;
private Uri mNotificationDataUri;
private Intent mIntent;
// TODO: add a List of the Status objects once created
@@ -62,7 +64,9 @@ public class PeopleSpaceTile implements Parcelable {
mLastInteractionTimestamp = b.mLastInteractionTimestamp;
mIsImportantConversation = b.mIsImportantConversation;
mIsHiddenConversation = b.mIsHiddenConversation;
mNotification = b.mNotification;
mNotificationKey = b.mNotificationKey;
mNotificationContent = b.mNotificationContent;
mNotificationDataUri = b.mNotificationDataUri;
mIntent = b.mIntent;
}
@@ -112,10 +116,18 @@ public class PeopleSpaceTile implements Parcelable {
/**
* If a notification is currently active that maps to the relevant shortcut ID, provides the
* {@link StatusBarNotification} associated.
* associated notification's key.
*/
public StatusBarNotification getNotification() {
return mNotification;
public String getNotificationKey() {
return mNotificationKey;
}
public CharSequence getNotificationContent() {
return mNotificationContent;
}
public Uri getNotificationDataUri() {
return mNotificationDataUri;
}
/**
@@ -129,6 +141,22 @@ public class PeopleSpaceTile implements Parcelable {
return mIntent;
}
/** Converts a {@link PeopleSpaceTile} into a {@link PeopleSpaceTile.Builder}. */
public PeopleSpaceTile.Builder toBuilder() {
PeopleSpaceTile.Builder builder =
new PeopleSpaceTile.Builder(mId, mUserName.toString(), mUserIcon, mIntent);
builder.setContactUri(mContactUri);
builder.setUid(mUid);
builder.setPackageName(mPackageName);
builder.setLastInteractionTimestamp(mLastInteractionTimestamp);
builder.setIsImportantConversation(mIsImportantConversation);
builder.setIsHiddenConversation(mIsHiddenConversation);
builder.setNotificationKey(mNotificationKey);
builder.setNotificationContent(mNotificationContent);
builder.setNotificationDataUri(mNotificationDataUri);
return builder;
}
/** Builder to create a {@link PeopleSpaceTile}. */
public static class Builder {
private String mId;
@@ -140,7 +168,9 @@ public class PeopleSpaceTile implements Parcelable {
private long mLastInteractionTimestamp;
private boolean mIsImportantConversation;
private boolean mIsHiddenConversation;
private StatusBarNotification mNotification;
private String mNotificationKey;
private CharSequence mNotificationContent;
private Uri mNotificationDataUri;
private Intent mIntent;
/** Builder for use only if a shortcut is not available for the tile. */
@@ -214,9 +244,21 @@ public class PeopleSpaceTile implements Parcelable {
return this;
}
/** Sets the associated notification. */
public Builder setNotification(StatusBarNotification notification) {
mNotification = notification;
/** Sets the associated notification's key. */
public Builder setNotificationKey(String notificationKey) {
mNotificationKey = notificationKey;
return this;
}
/** Sets the associated notification's content. */
public Builder setNotificationContent(CharSequence notificationContent) {
mNotificationContent = notificationContent;
return this;
}
/** Sets the associated notification's data URI. */
public Builder setNotificationDataUri(Uri notificationDataUri) {
mNotificationDataUri = notificationDataUri;
return this;
}
@@ -242,7 +284,9 @@ public class PeopleSpaceTile implements Parcelable {
mLastInteractionTimestamp = in.readLong();
mIsImportantConversation = in.readBoolean();
mIsHiddenConversation = in.readBoolean();
mNotification = in.readParcelable(StatusBarNotification.class.getClassLoader());
mNotificationKey = in.readString();
mNotificationContent = in.readCharSequence();
mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader());
mIntent = in.readParcelable(Intent.class.getClassLoader());
}
@@ -259,9 +303,11 @@ public class PeopleSpaceTile implements Parcelable {
dest.writeInt(mUid);
dest.writeString(mPackageName);
dest.writeLong(mLastInteractionTimestamp);
dest.writeParcelable(mNotification, flags);
dest.writeBoolean(mIsImportantConversation);
dest.writeBoolean(mIsHiddenConversation);
dest.writeString(mNotificationKey);
dest.writeCharSequence(mNotificationContent);
dest.writeParcelable(mNotificationDataUri, flags);
dest.writeParcelable(mIntent, flags);
}

View File

@@ -25,7 +25,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
@@ -35,8 +34,6 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -186,17 +183,34 @@ public class PeopleSpaceTileTest {
}
@Test
public void testNotification() {
Notification notification = new Notification.Builder(mContext, "test").build();
StatusBarNotification sbn = new StatusBarNotification("pkg" /* pkg */, "pkg" /* opPkg */,
1 /* id */, "" /* tag */, 0 /* uid */, 0 /* initialPid */, 0 /* score */,
notification, UserHandle.CURRENT, 0 /* postTime */);
public void testNotificationKey() {
PeopleSpaceTile tile = new PeopleSpaceTile
.Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
.setNotification(sbn)
.setNotificationKey("test")
.build();
assertThat(tile.getNotification()).isEqualTo(sbn);
assertThat(tile.getNotificationKey()).isEqualTo("test");
}
@Test
public void testNotificationContent() {
PeopleSpaceTile tile = new PeopleSpaceTile
.Builder(new ShortcutInfo.Builder(mContext, "123").build(), mLauncherApps)
.setNotificationContent("test")
.build();
assertThat(tile.getNotificationContent()).isEqualTo("test");
}
@Test
public void testNotificationDataUri() {
PeopleSpaceTile tile =
new PeopleSpaceTile.Builder(new ShortcutInfo.Builder(mContext, "123").build(),
mLauncherApps)
.setNotificationDataUri(Uri.parse("test"))
.build();
assertThat(tile.getNotificationDataUri()).isEqualTo(Uri.parse("test"));
}
@Test

View File

@@ -82,16 +82,25 @@
android:ellipsize="end" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/content"
android:paddingVertical="3dp"
android:paddingHorizontal="12dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
<LinearLayout
android:background="@drawable/people_space_content_background"
android:textSize="14sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLines="2"
android:ellipsize="end" />
android:layout_height="match_parent">
<TextView
android:id="@+id/content"
android:paddingVertical="3dp"
android:paddingHorizontal="12dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textSize="14sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLines="2"
android:ellipsize="end" />
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -136,8 +136,12 @@ public class PeopleSpaceActivity extends Activity {
editor.putString(String.valueOf(mAppWidgetId), tile.getId());
editor.commit();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(mContext);
Bundle options = new Bundle();
options.putParcelable(PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE, tile);
appWidgetManager.updateAppWidgetOptions(mAppWidgetId, options);
int[] widgetIds = appWidgetManager.getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class));
// TODO: Populate new widget with existing conversation notification, if there is any.
PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds, mAppWidgetManager,
mNotificationManager);
finishActivity();

View File

@@ -16,7 +16,10 @@
package com.android.systemui.people;
import static android.app.Notification.EXTRA_MESSAGES;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.people.ConversationChannel;
import android.app.people.IPeopleManager;
@@ -26,7 +29,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
@@ -34,20 +36,28 @@ import android.graphics.drawable.Drawable;
import android.icu.text.MeasureFormat;
import android.icu.util.Measure;
import android.icu.util.MeasureUnit;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
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.util.ArrayUtils;
import com.android.systemui.R;
import com.android.systemui.people.widget.LaunchConversationActivity;
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
import java.time.Duration;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -63,6 +73,13 @@ public class PeopleSpaceUtils {
private static final int DAYS_IN_A_WEEK = 7;
private static final int MIN_HOUR = 1;
private static final int ONE_DAY = 1;
public static final String OPTIONS_PEOPLE_SPACE_TILE = "options_people_space_tile";
/** Represents whether {@link StatusBarNotification} was posted or removed. */
public enum NotificationAction {
POSTED,
REMOVED
}
/** Returns a list of map entries corresponding to user's conversations. */
public static List<Map.Entry<Long, PeopleSpaceTile>> getTiles(
@@ -93,75 +110,42 @@ public class PeopleSpaceUtils {
/** Updates {@code appWidgetIds} with their associated conversation stored. */
public static void updateSingleConversationWidgets(Context context, int[] appWidgetIds,
AppWidgetManager appWidgetManager, INotificationManager notificationManager) {
PackageManager mPackageManager = context.getPackageManager();
IPeopleManager mPeopleManager = IPeopleManager.Stub.asInterface(
IPeopleManager peopleManager = IPeopleManager.Stub.asInterface(
ServiceManager.getService(Context.PEOPLE_SERVICE));
LauncherApps mLauncherApps = context.getSystemService(LauncherApps.class);
LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
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);
try {
List<Map.Entry<Long, PeopleSpaceTile>> shortcutInfos =
PeopleSpaceUtils.getTiles(
context, notificationManager,
mPeopleManager, mLauncherApps);
List<Map.Entry<Long, 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);
}
Optional<Map.Entry<Long, PeopleSpaceTile>> entry = shortcutInfos.stream().filter(
Optional<Map.Entry<Long, PeopleSpaceTile>> entry = tiles.stream().filter(
e -> e.getValue().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 = entry.get().getValue();
RemoteViews views = new RemoteViews(context.getPackageName(),
getLayout(tile));
PeopleSpaceTile tile =
augmentTileFromStorage(entry.get().getValue(), appWidgetManager,
appWidgetId);
String status = PeopleSpaceUtils.getLastInteractionString(context,
entry.get().getKey());
views.setTextViewText(R.id.status, status);
views.setTextViewText(R.id.name, tile.getUserName().toString());
RemoteViews views = createRemoteViews(context, tile, entry.get().getKey(),
appWidgetId);
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));
views.setImageViewBitmap(
R.id.package_icon,
PeopleSpaceUtils.convertDrawableToBitmap(
mPackageManager.getApplicationIcon(tile.getPackageName())
)
);
views.setImageViewIcon(R.id.person_icon, tile.getUserIcon());
// Tell the AppWidgetManager to perform an update on the current app widget.
appWidgetManager.updateAppWidget(appWidgetId, views);
}
} catch (Exception e) {
Log.e(TAG, "Failed to retrieve conversations to set tiles");
Log.e(TAG, "Exception updating single conversation widgets: " + e);
}
}
/** Returns the layout ID for the {@code tile}. */
private static int getLayout(PeopleSpaceTile tile) {
return tile.getNotification() == null ? R.layout.people_space_large_avatar_tile :
R.layout.people_space_small_avatar_tile;
}
/** 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) {
@@ -172,6 +156,152 @@ public class PeopleSpaceUtils {
.collect(Collectors.toList());
}
/** Augment {@link PeopleSpaceTile} with fields from stored tile. */
@VisibleForTesting
static PeopleSpaceTile augmentTileFromStorage(PeopleSpaceTile tile,
AppWidgetManager appWidgetManager, int appWidgetId) {
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
PeopleSpaceTile storedTile = options.getParcelable(OPTIONS_PEOPLE_SPACE_TILE);
if (storedTile == null) {
return tile;
}
return tile.toBuilder()
.setNotificationKey(storedTile.getNotificationKey())
.setNotificationContent(storedTile.getNotificationContent())
.setNotificationDataUri(storedTile.getNotificationDataUri())
.build();
}
/** If incoming notification changed tile, store the changes in the tile options. */
public static void storeNotificationChange(StatusBarNotification sbn,
NotificationAction notificationAction, AppWidgetManager appWidgetManager,
int appWidgetId) {
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
PeopleSpaceTile storedTile = options.getParcelable(OPTIONS_PEOPLE_SPACE_TILE);
if (notificationAction == PeopleSpaceUtils.NotificationAction.POSTED) {
if (DEBUG) Log.i(TAG, "Adding notification to storage, appWidgetId: " + appWidgetId);
Notification.MessagingStyle.Message message = getLastMessagingStyleMessage(sbn);
if (message == null) {
if (DEBUG) Log.i(TAG, "Notification doesn't have content, skipping.");
return;
}
storedTile = storedTile
.toBuilder()
.setNotificationKey(sbn.getKey())
.setNotificationContent(message.getText())
.setNotificationDataUri(message.getDataUri())
.build();
} else {
if (DEBUG) {
Log.i(TAG, "Removing notification from storage, appWidgetId: " + appWidgetId);
}
storedTile = storedTile
.toBuilder()
.setNotificationKey(null)
.setNotificationContent(null)
.setNotificationDataUri(null)
.build();
}
Bundle newOptions = new Bundle();
newOptions.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, storedTile);
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);
}
return createNotificationRemoteViews(context, tile, lastInteraction, 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);
views = setCommonRemoteViewsFields(context, views, tile, appWidgetId);
return views;
}
private static RemoteViews createNotificationRemoteViews(Context context,
PeopleSpaceTile tile, long lastInteraction, int appWidgetId)
throws Exception {
RemoteViews views = new RemoteViews(
context.getPackageName(), R.layout.people_space_small_avatar_tile);
Uri image = tile.getNotificationDataUri();
if (image != null) {
//TODO: Use NotificationInlineImageCache
views.setImageViewUri(R.id.image, image);
views.setViewVisibility(R.id.image, View.VISIBLE);
views.setViewVisibility(R.id.content, View.GONE);
} else {
views.setTextViewText(R.id.content, tile.getNotificationContent());
views.setViewVisibility(R.id.content, View.VISIBLE);
views.setViewVisibility(R.id.image, View.GONE);
}
views = setCommonRemoteViewsFields(context, views, tile, appWidgetId);
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());
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;
}
/** Gets the most recent {@link Notification.MessagingStyle.Message} from the notification. */
public static Notification.MessagingStyle.Message getLastMessagingStyleMessage(
StatusBarNotification sbn) {
Notification notification = sbn.getNotification();
if (notification == null) {
return null;
}
if (Notification.MessagingStyle.class.equals(notification.getNotificationStyle())
&& notification.extras != null) {
final Parcelable[] messages = notification.extras.getParcelableArray(EXTRA_MESSAGES);
if (!ArrayUtils.isEmpty(messages)) {
List<Notification.MessagingStyle.Message> sortedMessages =
Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
sortedMessages.sort(Collections.reverseOrder(
Comparator.comparing(Notification.MessagingStyle.Message::getTimestamp)));
return sortedMessages.get(0);
}
}
return null;
}
/** Returns the last interaction time with the user specified by {@code PeopleSpaceTile}. */
private static Long getLastInteraction(IPeopleManager peopleManager,
PeopleSpaceTile tile) {

View File

@@ -21,8 +21,10 @@ import android.app.NotificationChannel;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -35,6 +37,8 @@ import com.android.systemui.people.PeopleSpaceUtils;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -84,7 +88,6 @@ public class PeopleSpaceWidgetManager {
int[] widgetIds = mAppWidgetService.getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
);
if (widgetIds.length == 0) {
if (DEBUG) Log.d(TAG, "no widgets to update");
return;
@@ -93,6 +96,7 @@ public class PeopleSpaceWidgetManager {
if (DEBUG) Log.d(TAG, "updating " + widgetIds.length + " widgets");
boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
if (showSingleConversation) {
PeopleSpaceUtils.updateSingleConversationWidgets(mContext, widgetIds,
mAppWidgetManager, mNotificationManager);
@@ -106,6 +110,41 @@ public class PeopleSpaceWidgetManager {
}
}
/**
* Check if any existing People tiles match the incoming notification change, and store the
* change in the tile if so.
*/
public void storeNotificationChange(StatusBarNotification sbn,
PeopleSpaceUtils.NotificationAction notificationAction) {
if (DEBUG) Log.d(TAG, "storeNotificationChange called");
boolean showSingleConversation = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 0;
if (!showSingleConversation) {
return;
}
try {
int[] widgetIds = mAppWidgetService.getAppWidgetIds(
new ComponentName(mContext, PeopleSpaceWidgetProvider.class)
);
if (widgetIds.length == 0) {
return;
}
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
for (int widgetId : widgetIds) {
String shortcutId = sp.getString(String.valueOf(widgetId), null);
if (!Objects.equals(sbn.getShortcutId(), shortcutId)) {
continue;
}
if (DEBUG) Log.d(TAG, "Storing notification change, key:" + sbn.getKey());
PeopleSpaceUtils.storeNotificationChange(
sbn, notificationAction, mAppWidgetManager, widgetId);
}
} catch (Exception e) {
Log.e(TAG, "Exception: " + e);
}
}
/**
* Attaches the manager to the pipeline, making it ready to receive events. Should only be
* called once.
@@ -120,6 +159,7 @@ public class PeopleSpaceWidgetManager {
public void onNotificationPosted(
StatusBarNotification sbn, NotificationListenerService.RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted");
storeNotificationChange(sbn, PeopleSpaceUtils.NotificationAction.POSTED);
updateWidgets();
}
@@ -129,6 +169,7 @@ public class PeopleSpaceWidgetManager {
NotificationListenerService.RankingMap rankingMap
) {
if (DEBUG) Log.d(TAG, "onNotificationRemoved");
storeNotificationChange(sbn, PeopleSpaceUtils.NotificationAction.REMOVED);
updateWidgets();
}
@@ -138,6 +179,7 @@ public class PeopleSpaceWidgetManager {
NotificationListenerService.RankingMap rankingMap,
int reason) {
if (DEBUG) Log.d(TAG, "onNotificationRemoved with reason " + reason);
storeNotificationChange(sbn, PeopleSpaceUtils.NotificationAction.REMOVED);
updateWidgets();
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.people;
import static com.android.systemui.people.PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.Person;
import android.app.people.PeopleSpaceTile;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.Settings;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.SbnBuilder;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class PeopleSpaceUtilsTest extends SysuiTestCase {
private static final int WIDGET_ID_WITH_SHORTCUT = 1;
private static final int WIDGET_ID_WITHOUT_SHORTCUT = 2;
private static final String SHORTCUT_ID = "101";
private static final String NOTIFICATION_KEY = "notification_key";
private static final String NOTIFICATION_CONTENT = "notification_content";
@Mock
private NotificationListener mListenerService;
@Mock
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();
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
Bundle options = new Bundle();
options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, sPeopleSpaceTile);
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());
}
@Test
public void testGetLastMessagingStyleMessageNoMessage() {
Notification notification = new Notification.Builder(mContext, "test")
.setContentTitle("TEST_TITLE")
.setContentText("TEST_TEXT")
.setShortcutId(SHORTCUT_ID)
.build();
StatusBarNotification sbn = new SbnBuilder()
.setNotification(notification)
.build();
Notification.MessagingStyle.Message lastMessage =
PeopleSpaceUtils.getLastMessagingStyleMessage(sbn);
assertThat(lastMessage).isNull();
}
@Test
public void testGetLastMessagingStyleMessage() {
Notification notification = new Notification.Builder(mContext, "test")
.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))
)
.build();
StatusBarNotification sbn = new SbnBuilder()
.setNotification(notification)
.build();
Notification.MessagingStyle.Message lastMessage =
PeopleSpaceUtils.getLastMessagingStyleMessage(sbn);
assertThat(lastMessage.getText()).isEqualTo("text2");
}
@Test
public void testAugmentTileFromStorageWithNotification() {
PeopleSpaceTile tile =
new PeopleSpaceTile
.Builder("id", "userName", sIcon, 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);
}
@Test
public void testAugmentTileFromStorageWithoutNotification() {
PeopleSpaceTile tile =
new PeopleSpaceTile
.Builder("id", "userName", sIcon, new Intent())
.build();
PeopleSpaceTile actual = PeopleSpaceUtils
.augmentTileFromStorage(tile, mAppWidgetManager, WIDGET_ID_WITHOUT_SHORTCUT);
assertThat(actual.getNotificationKey()).isEqualTo(null);
assertThat(actual.getNotificationKey()).isEqualTo(null);
assertThat(actual.getNotificationDataUri()).isEqualTo(null);
}
}

View File

@@ -19,6 +19,8 @@ package com.android.systemui.people.widget;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static com.android.systemui.people.PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -30,15 +32,24 @@ import static org.mockito.Mockito.when;
import static java.util.Objects.requireNonNull;
import android.app.INotificationManager;
import android.app.Notification;
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;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.widget.RemoteViews;
@@ -46,9 +57,11 @@ import androidx.preference.PreferenceManager;
import androidx.test.filters.SmallTest;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationListener.NotificationHandler;
import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.collection.NoManSimulator;
import com.android.systemui.statusbar.notification.collection.NoManSimulator.NotifEvent;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -79,6 +92,9 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
private static final int WIDGET_ID_WITH_SHORTCUT = 1;
private static final int WIDGET_ID_WITHOUT_SHORTCUT = 2;
private static final String SHORTCUT_ID = "101";
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 PeopleSpaceWidgetManager mManager;
@@ -94,6 +110,26 @@ 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();
@@ -110,6 +146,18 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
mNoMan.addListener(serviceListener);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 2);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = sp.edit();
editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
editor.commit();
Bundle options = new Bundle();
options.putParcelable(OPTIONS_PEOPLE_SPACE_TILE, sPeopleSpaceTile);
when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT)))
.thenReturn(options);
when(mAppWidgetManager.getAppWidgetOptions(eq(WIDGET_ID_WITHOUT_SHORTCUT)))
.thenReturn(new Bundle());
}
@Test
@@ -123,7 +171,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
.setPkg(TEST_PACKAGE_A));
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
}
@@ -140,7 +187,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
.setPkg(TEST_PACKAGE_A));
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(), any(RemoteViews.class));
verify(mIAppWidgetService, never()).notifyAppWidgetViewDataChanged(any(), any(), anyInt());
}
@@ -156,7 +202,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
.setPkg(TEST_PACKAGE_A));
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
verify(mIAppWidgetService, times(1))
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
verify(mIAppWidgetService, never()).updateAppWidgetIds(any(), any(),
@@ -171,17 +216,12 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mINotificationManager.getConversations(true)).thenReturn(
new ParceledListSlice(getConversationWithShortcutId()));
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = sp.edit();
editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
editor.commit();
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setPkg(TEST_PACKAGE_A)
.setId(1));
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
verify(mIAppWidgetService, never())
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
@@ -198,10 +238,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
when(mINotificationManager.getConversations(true)).thenReturn(
new ParceledListSlice(getConversationWithShortcutId()));
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = sp.edit();
editor.putString(String.valueOf(WIDGET_ID_WITH_SHORTCUT), SHORTCUT_ID);
editor.commit();
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
@@ -212,7 +248,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
.setPkg(TEST_PACKAGE_B)
.setId(2));
verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
verify(mIAppWidgetService, never())
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
verify(mAppWidgetManager, times(2)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT),
@@ -234,7 +269,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
.setPkg(TEST_PACKAGE_B)
.setId(2));
verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
verify(mIAppWidgetService, times(2))
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
@@ -252,7 +286,6 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
mClock.advanceTime(4);
NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0);
verify(mIAppWidgetService, times(2)).getAppWidgetIds(any());
verify(mIAppWidgetService, times(2))
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
@@ -290,13 +323,124 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
UserHandle.getUserHandleForUid(0), channel, IMPORTANCE_HIGH);
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mIAppWidgetService, times(1)).getAppWidgetIds(any());
verify(mIAppWidgetService, times(1))
.notifyAppWidgetViewDataChanged(any(), eq(widgetIdsArray), anyInt());
verify(mAppWidgetManager, never()).updateAppWidget(anyInt(),
any(RemoteViews.class));
}
@Test
public void testDoNotUpdateNotificationPostedIfNoExistingTile() throws RemoteException {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
when(mINotificationManager.getConversations(true)).thenReturn(
new ParceledListSlice(getConversationWithShortcutId()));
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbn = createConversationNotification(OTHER_SHORTCUT_ID);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setPkg(TEST_PACKAGE_A)
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mAppWidgetManager, never())
.updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), any());
}
@Test
public void testDoNotUpdateNotificationRemovedIfNoExistingTile() throws RemoteException {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
when(mINotificationManager.getConversations(true)).thenReturn(
new ParceledListSlice(getConversationWithShortcutId()));
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbn = createConversationNotification(OTHER_SHORTCUT_ID);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setPkg(TEST_PACKAGE_A)
.setId(1));
mClock.advanceTime(4);
NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0);
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mAppWidgetManager, never())
.updateAppWidgetOptions(anyInt(), any());
}
@Test
public void testUpdateNotificationPostedIfExistingTile() throws RemoteException {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
when(mINotificationManager.getConversations(true)).thenReturn(
new ParceledListSlice(getConversationWithShortcutId()));
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbn = createConversationNotification(SHORTCUT_ID);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setPkg(TEST_PACKAGE_A)
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mAppWidgetManager, times(1))
.updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), any());
}
@Test
public void testDoNotUpdateNotificationPostedWithoutMessagesIfExistingTile()
throws RemoteException {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
when(mINotificationManager.getConversations(true)).thenReturn(
new ParceledListSlice(getConversationWithShortcutId()));
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
Notification notification = new Notification.Builder(mContext)
.setContentTitle("TEST_TITLE")
.setContentText("TEST_TEXT")
.setShortcutId(SHORTCUT_ID)
.build();
StatusBarNotification sbn = new SbnBuilder()
.setNotification(notification)
.build();
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setPkg(TEST_PACKAGE_A)
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mAppWidgetManager, never())
.updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), any());
}
@Test
public void testUpdateNotificationRemovedIfExistingTile() throws RemoteException {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0);
when(mINotificationManager.getConversations(true)).thenReturn(
new ParceledListSlice(getConversationWithShortcutId()));
int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT};
when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);
StatusBarNotification sbn = createConversationNotification(SHORTCUT_ID);
NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder()
.setSbn(sbn)
.setPkg(TEST_PACKAGE_A)
.setId(1));
mClock.advanceTime(MIN_LINGER_DURATION);
NotifEvent notif1b = mNoMan.retractNotif(notif1.sbn, 0);
mClock.advanceTime(MIN_LINGER_DURATION);
verify(mAppWidgetManager, times(2))
.updateAppWidgetOptions(eq(WIDGET_ID_WITH_SHORTCUT), any());
}
/** Returns a list of a single conversation associated with {@code SHORTCUT_ID}. */
private List<ConversationChannelWrapper> getConversationWithShortcutId() {
List<ConversationChannelWrapper> convos = new ArrayList<>();
@@ -306,4 +450,18 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase {
convos.add(convo1);
return convos;
}
private StatusBarNotification createConversationNotification(String shortcutId) {
Notification notification = new Notification.Builder(mContext)
.setContentTitle("TEST_TITLE")
.setContentText("TEST_TEXT")
.setShortcutId(shortcutId)
.setStyle(new Notification.MessagingStyle(sPerson)
.addMessage(new Notification.MessagingStyle.Message("text3", 10, sPerson))
)
.build();
return new SbnBuilder()
.setNotification(notification)
.build();
}
}