Merge "Show snoozed conversations in conversation header" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
66db87d0c0
@@ -19,6 +19,7 @@ package android.service.notification;
|
||||
import android.annotation.CurrentTimeMillisLong;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.TestApi;
|
||||
@@ -37,6 +38,7 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ParceledListSlice;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -53,6 +55,7 @@ import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -1566,6 +1569,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
private boolean mCanBubble;
|
||||
private boolean mVisuallyInterruptive;
|
||||
private boolean mIsConversation;
|
||||
private ShortcutInfo mShortcutInfo;
|
||||
|
||||
private static final int PARCEL_VERSION = 2;
|
||||
|
||||
@@ -1599,6 +1603,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
out.writeBoolean(mCanBubble);
|
||||
out.writeBoolean(mVisuallyInterruptive);
|
||||
out.writeBoolean(mIsConversation);
|
||||
out.writeParcelable(mShortcutInfo, flags);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -1620,7 +1625,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
mImportance = in.readInt();
|
||||
mImportanceExplanation = in.readCharSequence(); // may be null
|
||||
mOverrideGroupKey = in.readString(); // may be null
|
||||
mChannel = (NotificationChannel) in.readParcelable(cl); // may be null
|
||||
mChannel = in.readParcelable(cl); // may be null
|
||||
mOverridePeople = in.createStringArrayList();
|
||||
mSnoozeCriteria = in.createTypedArrayList(SnoozeCriterion.CREATOR);
|
||||
mShowBadge = in.readBoolean();
|
||||
@@ -1633,6 +1638,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
mCanBubble = in.readBoolean();
|
||||
mVisuallyInterruptive = in.readBoolean();
|
||||
mIsConversation = in.readBoolean();
|
||||
mShortcutInfo = in.readParcelable(cl);
|
||||
}
|
||||
|
||||
|
||||
@@ -1837,6 +1843,13 @@ public abstract class NotificationListenerService extends Service {
|
||||
return mIsConversation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public @Nullable ShortcutInfo getShortcutInfo() {
|
||||
return mShortcutInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -1849,7 +1862,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
int userSentiment, boolean hidden, long lastAudiblyAlertedMs,
|
||||
boolean noisy, ArrayList<Notification.Action> smartActions,
|
||||
ArrayList<CharSequence> smartReplies, boolean canBubble,
|
||||
boolean visuallyInterruptive, boolean isConversation) {
|
||||
boolean visuallyInterruptive, boolean isConversation, ShortcutInfo shortcutInfo) {
|
||||
mKey = key;
|
||||
mRank = rank;
|
||||
mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
|
||||
@@ -1872,6 +1885,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
mCanBubble = canBubble;
|
||||
mVisuallyInterruptive = visuallyInterruptive;
|
||||
mIsConversation = isConversation;
|
||||
mShortcutInfo = shortcutInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1898,7 +1912,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
other.mSmartReplies,
|
||||
other.mCanBubble,
|
||||
other.mVisuallyInterruptive,
|
||||
other.mIsConversation);
|
||||
other.mIsConversation,
|
||||
other.mShortcutInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1952,7 +1967,10 @@ public abstract class NotificationListenerService extends Service {
|
||||
&& Objects.equals(mSmartReplies, other.mSmartReplies)
|
||||
&& Objects.equals(mCanBubble, other.mCanBubble)
|
||||
&& Objects.equals(mVisuallyInterruptive, other.mVisuallyInterruptive)
|
||||
&& Objects.equals(mIsConversation, other.mIsConversation);
|
||||
&& Objects.equals(mIsConversation, other.mIsConversation)
|
||||
// Shortcutinfo doesn't have equals either; use id
|
||||
&& Objects.equals((mShortcutInfo == null ? 0 : mShortcutInfo.getId()),
|
||||
(other.mShortcutInfo == null ? 0 : other.mShortcutInfo.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,14 +68,14 @@ public interface NotificationPersonExtractorPlugin extends Plugin {
|
||||
public final String key;
|
||||
public final CharSequence name;
|
||||
public final Drawable avatar;
|
||||
public final PendingIntent clickIntent;
|
||||
public final Runnable clickRunnable;
|
||||
|
||||
public PersonData(String key, CharSequence name, Drawable avatar,
|
||||
PendingIntent clickIntent) {
|
||||
Runnable clickRunnable) {
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
this.avatar = avatar;
|
||||
this.clickIntent = clickIntent;
|
||||
this.clickRunnable = clickRunnable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,8 @@ public class ForegroundServiceNotificationListener {
|
||||
public void onEntryRemoved(
|
||||
NotificationEntry entry,
|
||||
NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
removeNotification(entry.getSbn());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -425,7 +425,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
|
||||
public void onEntryRemoved(
|
||||
NotificationEntry entry,
|
||||
@android.annotation.Nullable NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
BubbleController.this.onEntryRemoved(entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ import android.app.trust.TrustManager;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
import android.hardware.SensorPrivacyManager;
|
||||
import android.media.AudioManager;
|
||||
@@ -167,6 +169,12 @@ public class SystemServicesModule {
|
||||
return LatencyTracker.getInstance(context);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
static LauncherApps provideLauncherApps(Context context) {
|
||||
return context.getSystemService(LauncherApps.class);
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Singleton
|
||||
@Provides
|
||||
@@ -182,6 +190,12 @@ public class SystemServicesModule {
|
||||
return context.getSystemService(NotificationManager.class);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
static PackageManager providePackageManager(Context context) {
|
||||
return context.getPackageManager();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
static PackageManagerWrapper providePackageManagerWrapper() {
|
||||
|
||||
@@ -20,6 +20,7 @@ import static com.android.systemui.statusbar.RemoteInputController.processForRem
|
||||
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
|
||||
import static com.android.systemui.statusbar.phone.StatusBar.DEBUG;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.ComponentName;
|
||||
@@ -161,6 +162,15 @@ public class NotificationListener extends NotificationListenerWithPlugins {
|
||||
}
|
||||
}
|
||||
|
||||
public final void unsnoozeNotification(@NonNull String key) {
|
||||
if (!isBound()) return;
|
||||
try {
|
||||
getNotificationInterface().unsnoozeNotificationFromSystemListener(mWrapper, key);
|
||||
} catch (android.os.RemoteException ex) {
|
||||
Log.v(TAG, "Unable to contact notification manager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerAsSystemService() {
|
||||
try {
|
||||
registerAsSystemService(mContext,
|
||||
@@ -195,7 +205,8 @@ public class NotificationListener extends NotificationListenerWithPlugins {
|
||||
new ArrayList<>(),
|
||||
false,
|
||||
false,
|
||||
false
|
||||
false,
|
||||
null
|
||||
);
|
||||
}
|
||||
return ranking;
|
||||
|
||||
@@ -214,7 +214,8 @@ public class NotificationMediaManager implements Dumpable {
|
||||
public void onEntryRemoved(
|
||||
NotificationEntry entry,
|
||||
NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
onNotificationRemoved(entry.getKey());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -292,7 +292,8 @@ public class NotificationRemoteInputManager implements Dumpable {
|
||||
public void onEntryRemoved(
|
||||
@Nullable NotificationEntry entry,
|
||||
NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
// We're removing the notification, the smart controller can forget about it.
|
||||
mSmartReplyController.stopSending(entry);
|
||||
|
||||
|
||||
@@ -77,7 +77,8 @@ public class NotificationAlertingManager {
|
||||
public void onEntryRemoved(
|
||||
NotificationEntry entry,
|
||||
NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
stopAlerting(entry.getKey());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -92,7 +92,8 @@ public interface NotificationEntryListener {
|
||||
default void onEntryRemoved(
|
||||
NotificationEntry entry,
|
||||
@Nullable NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -477,7 +477,7 @@ public class NotificationEntryManager implements
|
||||
|
||||
mLogger.logNotifRemoved(entry.getKey(), removedByUser);
|
||||
for (NotificationEntryListener listener : mNotificationEntryListeners) {
|
||||
listener.onEntryRemoved(entry, visibility, removedByUser);
|
||||
listener.onEntryRemoved(entry, visibility, removedByUser, reason);
|
||||
}
|
||||
for (NotifCollectionListener listener : mNotifCollectionListeners) {
|
||||
// NEM doesn't have a good knowledge of reasons so defaulting to unknown.
|
||||
|
||||
@@ -59,7 +59,8 @@ public class NotificationListController {
|
||||
public void onEntryRemoved(
|
||||
NotificationEntry entry,
|
||||
NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
mListContainer.cleanUpViewStateForEntry(entry);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -153,6 +153,7 @@ public final class NotificationEntry extends ListEntry {
|
||||
public String remoteInputMimeType;
|
||||
public Uri remoteInputUri;
|
||||
private Notification.BubbleMetadata mBubbleMetadata;
|
||||
private ShortcutInfo mShortcutInfo;
|
||||
|
||||
/**
|
||||
* If {@link android.app.RemoteInput#getEditChoicesBeforeSending} is enabled, and the user is
|
||||
|
||||
@@ -213,7 +213,8 @@ public class NotificationLogger implements StateListener {
|
||||
public void onEntryRemoved(
|
||||
NotificationEntry entry,
|
||||
NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
if (removedByUser && visibility != null) {
|
||||
logNotificationClear(entry.getKey(), entry.getSbn(), visibility);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ data class PersonModel(
|
||||
val key: PersonKey,
|
||||
val name: CharSequence,
|
||||
val avatar: Drawable,
|
||||
val clickIntent: PendingIntent,
|
||||
val clickRunnable: Runnable,
|
||||
val userId: Int
|
||||
)
|
||||
|
||||
|
||||
@@ -17,20 +17,30 @@
|
||||
package com.android.systemui.statusbar.notification.people
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Context
|
||||
import android.content.pm.LauncherApps
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.pm.UserInfo
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.UserManager
|
||||
import android.service.notification.NotificationListenerService
|
||||
import android.service.notification.NotificationListenerService.REASON_SNOOZED
|
||||
import android.service.notification.StatusBarNotification
|
||||
import android.util.IconDrawableFactory
|
||||
import android.util.SparseArray
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import com.android.internal.statusbar.NotificationVisibility
|
||||
import com.android.internal.widget.MessagingGroup
|
||||
import com.android.settingslib.notification.ConversationIconFactory
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.plugins.NotificationPersonExtractorPlugin
|
||||
import com.android.systemui.statusbar.NotificationListener
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryListener
|
||||
import com.android.systemui.statusbar.notification.NotificationEntryManager
|
||||
@@ -69,7 +79,7 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor(
|
||||
|
||||
override fun extractPerson(sbn: StatusBarNotification) =
|
||||
plugin?.extractPerson(sbn)?.run {
|
||||
PersonModel(key, name, avatar, clickIntent, sbn.user.identifier)
|
||||
PersonModel(key, name, avatar, clickRunnable, sbn.user.identifier)
|
||||
}
|
||||
|
||||
override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn)
|
||||
@@ -80,17 +90,26 @@ class NotificationPersonExtractorPluginBoundary @Inject constructor(
|
||||
|
||||
@Singleton
|
||||
class PeopleHubDataSourceImpl @Inject constructor(
|
||||
private val notificationEntryManager: NotificationEntryManager,
|
||||
private val extractor: NotificationPersonExtractor,
|
||||
private val userManager: UserManager,
|
||||
@Background private val bgExecutor: Executor,
|
||||
@Main private val mainExecutor: Executor,
|
||||
private val notifLockscreenUserMgr: NotificationLockscreenUserManager
|
||||
) : DataSource<PeopleHubModel> {
|
||||
private val notificationEntryManager: NotificationEntryManager,
|
||||
private val extractor: NotificationPersonExtractor,
|
||||
private val userManager: UserManager,
|
||||
private val launcherApps: LauncherApps,
|
||||
private val packageManager: PackageManager,
|
||||
private val c: Context,
|
||||
private val notificationListener: NotificationListener,
|
||||
@Background private val bgExecutor: Executor,
|
||||
@Main private val mainExecutor: Executor,
|
||||
private val notifLockscreenUserMgr: NotificationLockscreenUserManager,
|
||||
private val peopleNotificationIdentifier: PeopleNotificationIdentifier
|
||||
) : DataSource<PeopleHubModel> {
|
||||
|
||||
private var userChangeSubscription: Subscription? = null
|
||||
private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
|
||||
private val peopleHubManagerForUser = SparseArray<PeopleHubManager>()
|
||||
val context: Context = c.applicationContext
|
||||
val iconFactory = ConversationIconFactory(context, launcherApps, packageManager,
|
||||
IconDrawableFactory.newInstance(context), context.resources.getDimensionPixelSize(
|
||||
R.dimen.notification_guts_conversation_icon_size))
|
||||
|
||||
private val notificationEntryListener = object : NotificationEntryListener {
|
||||
override fun onEntryInflated(entry: NotificationEntry) = addVisibleEntry(entry)
|
||||
@@ -102,18 +121,23 @@ class PeopleHubDataSourceImpl @Inject constructor(
|
||||
override fun onEntryRemoved(
|
||||
entry: NotificationEntry,
|
||||
visibility: NotificationVisibility?,
|
||||
removedByUser: Boolean
|
||||
) = removeVisibleEntry(entry)
|
||||
removedByUser: Boolean,
|
||||
reason: Int
|
||||
) = removeVisibleEntry(entry, reason)
|
||||
}
|
||||
|
||||
private fun removeVisibleEntry(entry: NotificationEntry) {
|
||||
private fun removeVisibleEntry(entry: NotificationEntry, reason: Int) {
|
||||
(extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey())?.let { key ->
|
||||
val userId = entry.sbn.user.identifier
|
||||
bgExecutor.execute {
|
||||
val parentId = userManager.getProfileParent(userId)?.id ?: userId
|
||||
mainExecutor.execute {
|
||||
if (peopleHubManagerForUser[parentId]?.removeActivePerson(key) == true) {
|
||||
updateUi()
|
||||
if (reason == REASON_SNOOZED) {
|
||||
if (peopleHubManagerForUser[parentId]?.migrateActivePerson(key) == true) {
|
||||
updateUi()
|
||||
}
|
||||
} else {
|
||||
peopleHubManagerForUser[parentId]?.removeActivePerson(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,7 +145,7 @@ class PeopleHubDataSourceImpl @Inject constructor(
|
||||
}
|
||||
|
||||
private fun addVisibleEntry(entry: NotificationEntry) {
|
||||
(extractor.extractPerson(entry.sbn) ?: entry.extractPerson())?.let { personModel ->
|
||||
entry.extractPerson()?.let { personModel ->
|
||||
val userId = entry.sbn.user.identifier
|
||||
bgExecutor.execute {
|
||||
val parentId = userManager.getProfileParent(userId)?.id ?: userId
|
||||
@@ -180,6 +204,34 @@ class PeopleHubDataSourceImpl @Inject constructor(
|
||||
listener.onDataChanged(model)
|
||||
}
|
||||
}
|
||||
|
||||
private fun NotificationEntry.extractPerson(): PersonModel? {
|
||||
if (!peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) {
|
||||
return null
|
||||
}
|
||||
val clickRunnable = Runnable { notificationListener.unsnoozeNotification(key) }
|
||||
val extras = sbn.notification.extras
|
||||
val name = ranking.shortcutInfo?.shortLabel
|
||||
?: extras.getString(Notification.EXTRA_CONVERSATION_TITLE)
|
||||
?: extras.getString(Notification.EXTRA_TITLE)
|
||||
?: return null
|
||||
val drawable = ranking.shortcutInfo?.getIcon(iconFactory, sbn, ranking)
|
||||
?: iconFactory.getConversationDrawable(extractAvatarFromRow(this), sbn.packageName,
|
||||
sbn.uid, ranking.channel.isImportantConversation)
|
||||
|
||||
return PersonModel(key, name, drawable, clickRunnable, sbn.user.identifier)
|
||||
}
|
||||
|
||||
private fun ShortcutInfo.getIcon(iconFactory: ConversationIconFactory,
|
||||
sbn: StatusBarNotification,
|
||||
ranking: NotificationListenerService.Ranking): Drawable? {
|
||||
return iconFactory.getConversationDrawable(ranking.shortcutInfo, sbn.packageName, sbn.uid,
|
||||
ranking.channel.isImportantConversation)
|
||||
}
|
||||
|
||||
private fun NotificationEntry.extractPersonKey(): PersonKey? =
|
||||
// TODO migrate to shortcut id when snoozing is conversation wide
|
||||
if (peopleNotificationIdentifier.isPeopleNotification(sbn, ranking)) key else null
|
||||
}
|
||||
|
||||
private fun NotificationLockscreenUserManager.registerListener(
|
||||
@@ -201,7 +253,7 @@ class PeopleHubManager {
|
||||
// People that were once "active" and have been dismissed, and so can be displayed in the hub
|
||||
private val inactivePeople = ArrayDeque<PersonModel>(MAX_STORED_INACTIVE_PEOPLE)
|
||||
|
||||
fun removeActivePerson(key: PersonKey): Boolean {
|
||||
fun migrateActivePerson(key: PersonKey): Boolean {
|
||||
activePeople.remove(key)?.let { data ->
|
||||
if (inactivePeople.size >= MAX_STORED_INACTIVE_PEOPLE) {
|
||||
inactivePeople.removeLast()
|
||||
@@ -212,6 +264,10 @@ class PeopleHubManager {
|
||||
return false
|
||||
}
|
||||
|
||||
fun removeActivePerson(key: PersonKey) {
|
||||
activePeople.remove(key)
|
||||
}
|
||||
|
||||
fun addActivePerson(person: PersonModel): Boolean {
|
||||
activePeople[person.key] = person
|
||||
return inactivePeople.removeIf { it.key == person.key }
|
||||
@@ -229,19 +285,6 @@ private val ViewGroup.children
|
||||
|
||||
private fun ViewGroup.childrenWithId(id: Int): Sequence<View> = children.filter { it.id == id }
|
||||
|
||||
private fun NotificationEntry.extractPerson(): PersonModel? {
|
||||
if (!isMessagingNotification()) {
|
||||
return null
|
||||
}
|
||||
val clickIntent = sbn.notification.contentIntent ?: return null
|
||||
val extras = sbn.notification.extras
|
||||
val name = extras.getString(Notification.EXTRA_CONVERSATION_TITLE)
|
||||
?: extras.getString(Notification.EXTRA_TITLE)
|
||||
?: return null
|
||||
val drawable = extractAvatarFromRow(this) ?: return null
|
||||
return PersonModel(key, name, drawable, clickIntent, sbn.user.identifier)
|
||||
}
|
||||
|
||||
fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
|
||||
entry.row
|
||||
?.childrenWithId(R.id.expanded)
|
||||
@@ -261,8 +304,3 @@ fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
|
||||
}
|
||||
?.firstOrNull()
|
||||
|
||||
private fun NotificationEntry.extractPersonKey(): PersonKey? =
|
||||
if (isMessagingNotification()) key else null
|
||||
|
||||
private fun NotificationEntry.isMessagingNotification() =
|
||||
sbn.notification.notificationStyle == Notification.MessagingStyle::class.java
|
||||
|
||||
@@ -102,30 +102,19 @@ private class PeopleHubDataListenerImpl(
|
||||
@Singleton
|
||||
class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor(
|
||||
private val activityStarter: ActivityStarter,
|
||||
private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubModel>,
|
||||
private val settingChangeSource: DataSource<@JvmSuppressWildcards Boolean>
|
||||
private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubModel>
|
||||
) : DataSource<PeopleHubViewModelFactory> {
|
||||
|
||||
override fun registerListener(listener: DataListener<PeopleHubViewModelFactory>): Subscription {
|
||||
var stripEnabled = false
|
||||
var model: PeopleHubModel? = null
|
||||
|
||||
fun updateListener() {
|
||||
// don't invoke listener until we've received our first model
|
||||
model?.let { model ->
|
||||
val factory =
|
||||
if (stripEnabled) PeopleHubViewModelFactoryImpl(model, activityStarter)
|
||||
else EmptyViewModelFactory
|
||||
val factory = PeopleHubViewModelFactoryImpl(model, activityStarter)
|
||||
listener.onDataChanged(factory)
|
||||
}
|
||||
}
|
||||
|
||||
val settingSub = settingChangeSource.registerListener(object : DataListener<Boolean> {
|
||||
override fun onDataChanged(data: Boolean) {
|
||||
stripEnabled = data
|
||||
updateListener()
|
||||
}
|
||||
})
|
||||
val dataSub = dataSource.registerListener(object : DataListener<PeopleHubModel> {
|
||||
override fun onDataChanged(data: PeopleHubModel) {
|
||||
model = data
|
||||
@@ -134,7 +123,6 @@ class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor(
|
||||
})
|
||||
return object : Subscription {
|
||||
override fun unsubscribe() {
|
||||
settingSub.unsubscribe()
|
||||
dataSub.unsubscribe()
|
||||
}
|
||||
}
|
||||
@@ -155,11 +143,7 @@ private class PeopleHubViewModelFactoryImpl(
|
||||
override fun createWithAssociatedClickView(view: View): PeopleHubViewModel {
|
||||
val personViewModels = model.people.asSequence().map { personModel ->
|
||||
val onClick = {
|
||||
activityStarter.startPendingIntentDismissingKeyguard(
|
||||
personModel.clickIntent,
|
||||
null,
|
||||
view
|
||||
)
|
||||
personModel.clickRunnable.run()
|
||||
}
|
||||
PersonViewModel(personModel.name, personModel.avatar, onClick)
|
||||
}
|
||||
|
||||
@@ -216,15 +216,7 @@ public class NotificationConversationInfo extends LinearLayout implements
|
||||
if (TextUtils.isEmpty(mConversationId)) {
|
||||
throw new IllegalArgumentException("Does not have required information");
|
||||
}
|
||||
// TODO: consider querying this earlier in the notification pipeline and passing it in
|
||||
LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery()
|
||||
.setPackage(mPackageName)
|
||||
.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED)
|
||||
.setShortcutIds(Arrays.asList(mConversationId));
|
||||
List<ShortcutInfo> shortcuts = mLauncherApps.getShortcuts(query, mSbn.getUser());
|
||||
if (shortcuts != null && !shortcuts.isEmpty()) {
|
||||
mShortcutInfo = shortcuts.get(0);
|
||||
}
|
||||
mShortcutInfo = entry.getRanking().getShortcutInfo();
|
||||
|
||||
mIsBubbleable = mEntry.getBubbleMetadata() != null
|
||||
&& Settings.Global.getInt(mContext.getContentResolver(),
|
||||
|
||||
@@ -172,7 +172,7 @@ public class LightsOutNotifController {
|
||||
|
||||
@Override
|
||||
public void onEntryRemoved(@Nullable NotificationEntry entry,
|
||||
NotificationVisibility visibility, boolean removedByUser) {
|
||||
NotificationVisibility visibility, boolean removedByUser, int reason) {
|
||||
updateLightsOutView();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -196,7 +196,8 @@ public class NotificationGroupAlertTransferHelper implements OnHeadsUpChangedLis
|
||||
public void onEntryRemoved(
|
||||
@Nullable NotificationEntry entry,
|
||||
NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
// Removes any alerts pending on this entry. Note that this will not stop any inflation
|
||||
// tasks started by a transfer, so this should only be used as clean-up for when
|
||||
// inflation is stopped and the pending alert no longer needs to happen.
|
||||
|
||||
@@ -199,7 +199,8 @@ public class StatusBarNotificationPresenter implements NotificationPresenter,
|
||||
public void onEntryRemoved(
|
||||
@Nullable NotificationEntry entry,
|
||||
NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser,
|
||||
int reason) {
|
||||
StatusBarNotificationPresenter.this.onNotificationRemoved(
|
||||
entry.getKey(), entry.getSbn());
|
||||
if (removedByUser) {
|
||||
|
||||
@@ -73,7 +73,7 @@ public class RemoteInputUriController {
|
||||
private final NotificationEntryListener mInlineUriListener = new NotificationEntryListener() {
|
||||
@Override
|
||||
public void onEntryRemoved(NotificationEntry entry, NotificationVisibility visibility,
|
||||
boolean removedByUser) {
|
||||
boolean removedByUser, int reason) {
|
||||
try {
|
||||
mStatusBarManagerService.clearInlineReplyUriPermissions(entry.getKey());
|
||||
} catch (RemoteException ex) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.systemui;
|
||||
|
||||
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
import static junit.framework.TestCase.fail;
|
||||
@@ -528,7 +530,8 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
|
||||
.setSbn(notification)
|
||||
.build(),
|
||||
null,
|
||||
false);
|
||||
false,
|
||||
REASON_APP_CANCEL);
|
||||
}
|
||||
|
||||
private void entryAdded(StatusBarNotification notification, int importance) {
|
||||
|
||||
@@ -685,7 +685,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
// Removes the notification
|
||||
mEntryListener.onEntryRemoved(mRow.getEntry(), null, false);
|
||||
mEntryListener.onEntryRemoved(mRow.getEntry(), null, false, REASON_APP_CANCEL);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
}
|
||||
|
||||
@@ -827,7 +827,7 @@ public class BubbleControllerTest extends SysuiTestCase {
|
||||
mBubbleController.handleDismissalInterception(groupSummary.getEntry());
|
||||
|
||||
// WHEN the summary is cancelled by the app
|
||||
mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, true);
|
||||
mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, false, REASON_APP_CANCEL);
|
||||
|
||||
// THEN the summary and its children are removed from bubble data
|
||||
assertFalse(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager.Importance;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
import android.service.notification.SnoozeCriterion;
|
||||
|
||||
@@ -53,6 +54,7 @@ public class RankingBuilder {
|
||||
private boolean mCanBubble = false;
|
||||
private boolean mIsVisuallyInterruptive = false;
|
||||
private boolean mIsConversation = false;
|
||||
private ShortcutInfo mShortcutInfo = null;
|
||||
|
||||
public RankingBuilder() {
|
||||
}
|
||||
@@ -79,6 +81,7 @@ public class RankingBuilder {
|
||||
mCanBubble = ranking.canBubble();
|
||||
mIsVisuallyInterruptive = ranking.visuallyInterruptive();
|
||||
mIsConversation = ranking.isConversation();
|
||||
mShortcutInfo = ranking.getShortcutInfo();
|
||||
}
|
||||
|
||||
public Ranking build() {
|
||||
@@ -104,7 +107,8 @@ public class RankingBuilder {
|
||||
mSmartReplies,
|
||||
mCanBubble,
|
||||
mIsVisuallyInterruptive,
|
||||
mIsConversation);
|
||||
mIsConversation,
|
||||
mShortcutInfo);
|
||||
return ranking;
|
||||
}
|
||||
|
||||
@@ -189,6 +193,11 @@ public class RankingBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public RankingBuilder setShortcutInfo(ShortcutInfo shortcutInfo) {
|
||||
mShortcutInfo = shortcutInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
public RankingBuilder setImportance(@Importance int importance) {
|
||||
mImportance = importance;
|
||||
return this;
|
||||
|
||||
@@ -143,7 +143,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
IMPORTANCE_DEFAULT,
|
||||
null, null,
|
||||
null, null, null, true, sentiment, false, -1, false, null, null, false, false,
|
||||
false);
|
||||
false, null);
|
||||
return true;
|
||||
}).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
|
||||
}
|
||||
@@ -162,7 +162,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
null, null,
|
||||
null, null, null, true,
|
||||
Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
|
||||
false, smartActions, null, false, false, false);
|
||||
false, smartActions, null, false, false, false, null);
|
||||
return true;
|
||||
}).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
|
||||
}
|
||||
@@ -254,7 +254,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
|
||||
verify(mPresenter).updateNotificationViews();
|
||||
verify(mEntryListener).onEntryRemoved(
|
||||
eq(mEntry), any(), eq(false) /* removedByUser */);
|
||||
eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
|
||||
verify(mRow).setRemoved();
|
||||
|
||||
assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
|
||||
@@ -266,7 +266,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
|
||||
|
||||
verify(mEntryListener, never()).onEntryRemoved(
|
||||
eq(mEntry), any(), eq(false) /* removedByUser */);
|
||||
eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -275,7 +275,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
|
||||
|
||||
verify(mEntryListener, never()).onEntryRemoved(
|
||||
eq(mEntry), any(), eq(false /* removedByUser */));
|
||||
eq(mEntry), any(), eq(false /* removedByUser */), eq(UNDEFINED_DISMISS_REASON));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -356,7 +356,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
verify(extender).setShouldManageLifetime(mEntry, true);
|
||||
// THEN the notification is retained
|
||||
assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
|
||||
verify(mEntryListener, never()).onEntryRemoved(eq(mEntry), any(), eq(false));
|
||||
verify(mEntryListener, never()).onEntryRemoved(
|
||||
eq(mEntry), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -374,7 +375,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
|
||||
// THEN the notification is removed
|
||||
assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
|
||||
verify(mEntryListener).onEntryRemoved(eq(mEntry), any(), eq(false));
|
||||
verify(mEntryListener).onEntryRemoved(
|
||||
eq(mEntry), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -447,7 +449,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
// THEN the interceptor intercepts & the entry is not removed & no listeners are called
|
||||
assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
|
||||
verify(mEntryListener, never()).onEntryRemoved(eq(mEntry),
|
||||
any(NotificationVisibility.class), anyBoolean());
|
||||
any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -466,7 +468,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
|
||||
// THEN the interceptor intercepts & the entry is not removed & no listeners are called
|
||||
assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
|
||||
verify(mEntryListener, atLeastOnce()).onEntryRemoved(eq(mEntry),
|
||||
any(NotificationVisibility.class), anyBoolean());
|
||||
any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
|
||||
}
|
||||
|
||||
private NotificationEntry createNotification() {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.systemui.statusbar.notification;
|
||||
|
||||
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@@ -87,7 +89,8 @@ public class NotificationListControllerTest extends SysuiTestCase {
|
||||
mEntryListener.onEntryRemoved(
|
||||
entry,
|
||||
NotificationVisibility.obtain(entry.getKey(), 0, 0, true),
|
||||
false);
|
||||
false,
|
||||
UNDEFINED_DISMISS_REASON);
|
||||
verify(mListContainer).cleanUpViewStateForEntry(entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.SnoozeCriterion;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
@@ -266,4 +267,9 @@ public class NotificationEntryBuilder {
|
||||
mRankingBuilder.setSmartReplies(smartReplies);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NotificationEntryBuilder setShortcutInfo(ShortcutInfo shortcutInfo) {
|
||||
mRankingBuilder.setShortcutInfo(shortcutInfo);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,15 +101,13 @@ class PeopleHubViewControllerTest : SysuiTestCase() {
|
||||
|
||||
@Test
|
||||
fun testViewModelDataSourceTransformsModel() {
|
||||
val fakeClickIntent = PendingIntent.getActivity(context, 0, Intent("action"), 0)
|
||||
val fakePerson = fakePersonModel("id", "name", fakeClickIntent)
|
||||
val fakeClickRunnable = mock(Runnable::class.java)
|
||||
val fakePerson = fakePersonModel("id", "name", fakeClickRunnable)
|
||||
val fakeModel = PeopleHubModel(listOf(fakePerson))
|
||||
val fakeModelDataSource = FakeDataSource(fakeModel)
|
||||
val fakeSettingDataSource = FakeDataSource(true)
|
||||
val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl(
|
||||
mockActivityStarter,
|
||||
fakeModelDataSource,
|
||||
fakeSettingDataSource
|
||||
fakeModelDataSource
|
||||
)
|
||||
val fakeListener = FakeDataListener<PeopleHubViewModelFactory>()
|
||||
val mockClickView = mock(View::class.java)
|
||||
@@ -126,35 +124,7 @@ class PeopleHubViewControllerTest : SysuiTestCase() {
|
||||
|
||||
people[0].onClick()
|
||||
|
||||
verify(mockActivityStarter).startPendingIntentDismissingKeyguard(
|
||||
same(fakeClickIntent),
|
||||
any(),
|
||||
same(mockClickView)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testViewModelDataSource_notVisibleIfSettingDisabled() {
|
||||
val fakeClickIntent = PendingIntent.getActivity(context, 0, Intent("action"), 0)
|
||||
val fakePerson = fakePersonModel("id", "name", fakeClickIntent)
|
||||
val fakeModel = PeopleHubModel(listOf(fakePerson))
|
||||
val fakeModelDataSource = FakeDataSource(fakeModel)
|
||||
val fakeSettingDataSource = FakeDataSource(false)
|
||||
val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl(
|
||||
mockActivityStarter,
|
||||
fakeModelDataSource,
|
||||
fakeSettingDataSource
|
||||
)
|
||||
val fakeListener = FakeDataListener<PeopleHubViewModelFactory>()
|
||||
val mockClickView = mock(View::class.java)
|
||||
|
||||
factoryDataSource.registerListener(fakeListener)
|
||||
|
||||
val viewModel = (fakeListener.lastSeen as Maybe.Just).value
|
||||
.createWithAssociatedClickView(mockClickView)
|
||||
assertThat(viewModel.isVisible).isFalse()
|
||||
val people = viewModel.people.toList()
|
||||
assertThat(people.size).isEqualTo(0)
|
||||
verify(fakeClickRunnable).run()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,10 +148,10 @@ private fun <T> castNull(): T = null as T
|
||||
private fun fakePersonModel(
|
||||
id: String,
|
||||
name: CharSequence,
|
||||
clickIntent: PendingIntent,
|
||||
clickRunnable: Runnable,
|
||||
userId: Int = 0
|
||||
): PersonModel =
|
||||
PersonModel(id, name, mock(Drawable::class.java), clickIntent, userId)
|
||||
PersonModel(id, name, mock(Drawable::class.java), clickRunnable, userId)
|
||||
|
||||
private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
|
||||
PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
|
||||
|
||||
@@ -198,7 +198,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
.build();
|
||||
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
|
||||
notification, UserHandle.CURRENT, null, 0);
|
||||
mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
|
||||
mEntry = new NotificationEntryBuilder().setSbn(mSbn).setShortcutInfo(mShortcutInfo).build();
|
||||
|
||||
PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
|
||||
new Intent(mContext, BubblesTestActivity.class), 0);
|
||||
@@ -207,7 +207,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
|
||||
.createIntentBubble(bubbleIntent,
|
||||
Icon.createWithResource(mContext, R.drawable.android)).build())
|
||||
.build();
|
||||
mBubbleEntry = new NotificationEntryBuilder().setSbn(mBubbleSbn).build();
|
||||
mBubbleEntry = new NotificationEntryBuilder()
|
||||
.setSbn(mBubbleSbn)
|
||||
.setShortcutInfo(mShortcutInfo)
|
||||
.build();
|
||||
|
||||
mConversationChannel = new NotificationChannel(
|
||||
TEST_CHANNEL + " : " + CONVERSATION_ID, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
|
||||
|
||||
@@ -283,7 +283,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
false,
|
||||
null);
|
||||
mRankingMap = new NotificationListenerService.RankingMap(new Ranking[] {ranking});
|
||||
|
||||
TestableLooper.get(this).processAllMessages();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
|
||||
import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
|
||||
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
@@ -205,7 +206,8 @@ public class LightsOutNotifControllerTest extends SysuiTestCase {
|
||||
// WHEN all active notifications are removed
|
||||
when(mEntryManager.hasActiveNotifications()).thenReturn(false);
|
||||
assertFalse(mLightsOutNotifController.shouldShowDot());
|
||||
mEntryListener.onEntryRemoved(mock(NotificationEntry.class), null, false);
|
||||
mEntryListener.onEntryRemoved(
|
||||
mock(NotificationEntry.class), null, false, REASON_CANCEL_ALL);
|
||||
|
||||
// THEN we shouldn't see the dot view
|
||||
assertIsShowingDot(false);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
|
||||
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -254,7 +255,8 @@ public class NotificationGroupAlertTransferHelperTest extends SysuiTestCase {
|
||||
mGroupManager.onEntryAdded(summaryEntry);
|
||||
mGroupManager.onEntryAdded(childEntry);
|
||||
|
||||
mNotificationEntryListener.onEntryRemoved(childEntry, null, false);
|
||||
mNotificationEntryListener.onEntryRemoved(
|
||||
childEntry, null, false, UNDEFINED_DISMISS_REASON);
|
||||
|
||||
assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
|
||||
}
|
||||
|
||||
@@ -8575,7 +8575,8 @@ public class NotificationManagerService extends SystemService {
|
||||
record.getSmartReplies(),
|
||||
record.canBubble(),
|
||||
record.isInterruptive(),
|
||||
record.isConversation()
|
||||
record.isConversation(),
|
||||
record.getShortcutInfo()
|
||||
);
|
||||
rankings.add(ranking);
|
||||
}
|
||||
|
||||
@@ -1344,6 +1344,10 @@ public final class NotificationRecord {
|
||||
mShortcutInfo = shortcutInfo;
|
||||
}
|
||||
|
||||
public ShortcutInfo getShortcutInfo() {
|
||||
return mShortcutInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this notification is a conversation notification.
|
||||
*/
|
||||
|
||||
@@ -35,9 +35,12 @@ import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Person;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Binder;
|
||||
@@ -118,6 +121,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
assertEquals(canBubble(i), ranking.canBubble());
|
||||
assertEquals(visuallyInterruptive(i), ranking.visuallyInterruptive());
|
||||
assertEquals(isConversation(i), ranking.isConversation());
|
||||
assertEquals(getShortcutInfo(i).getId(), ranking.getShortcutInfo().getId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +190,8 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
(ArrayList) tweak.getSmartReplies(),
|
||||
tweak.canBubble(),
|
||||
tweak.visuallyInterruptive(),
|
||||
tweak.isConversation()
|
||||
tweak.isConversation(),
|
||||
tweak.getShortcutInfo()
|
||||
);
|
||||
assertNotEquals(nru, nru2);
|
||||
}
|
||||
@@ -264,7 +269,8 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
getSmartReplies(key, i),
|
||||
canBubble(i),
|
||||
visuallyInterruptive(i),
|
||||
isConversation(i)
|
||||
isConversation(i),
|
||||
getShortcutInfo(i)
|
||||
);
|
||||
rankings[i] = ranking;
|
||||
}
|
||||
@@ -377,6 +383,17 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
return index % 4 == 0;
|
||||
}
|
||||
|
||||
private ShortcutInfo getShortcutInfo(int index) {
|
||||
ShortcutInfo si = new ShortcutInfo(
|
||||
index, String.valueOf(index), "packageName", new ComponentName("1", "1"), null,
|
||||
"title", 0, "titleResName", "text", 0, "textResName",
|
||||
"disabledMessage", 0, "disabledMessageResName",
|
||||
null, null, 0, null, 0, 0,
|
||||
0, "iconResName", "bitmapPath", 0,
|
||||
null, null);
|
||||
return si;
|
||||
}
|
||||
|
||||
private void assertActionsEqual(
|
||||
List<Notification.Action> expecteds, List<Notification.Action> actuals) {
|
||||
assertEquals(expecteds.size(), actuals.size());
|
||||
@@ -411,6 +428,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
|
||||
assertEquals(comment, a.getSmartReplies(), b.getSmartReplies());
|
||||
assertEquals(comment, a.canBubble(), b.canBubble());
|
||||
assertEquals(comment, a.isConversation(), b.isConversation());
|
||||
assertEquals(comment, a.getShortcutInfo().getId(), b.getShortcutInfo().getId());
|
||||
assertActionsEqual(a.getSmartActions(), b.getSmartActions());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user