From 9b2a480ceb42bb7a79a1ff532dac42b0f407a88f Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Fri, 8 May 2020 11:56:18 -0400 Subject: [PATCH] Create a shim for StatusBarManager click methods `StatusBarManager#onNotificationClick` and `StatusBarManager#onNotificationActionClick` are signals we send to system server about notification clicks. This CL adds a shim so that we can have an in-process callback about the exact same events. This CL also adds NotificationInteractionTracker, which basically just merges the NotificationClickNotifier callbacks with the notification collection and will be able to answer the question "has the user interacted with this notification" Lastly, this modifies the logic in ForegroundServiceLifetimeExtender which now checks the interaction flag for notifications. So if a user tapped on a notification action (for instance) which _then_ triggers a notification cancel, it will succeed. It _does not_ as of yet release the notification from lifetime extension upon interaction. So if a notification is canceled and then interacted with, it will still live the full amount of time. Test: atest SystemUITests Bug: 144324894 Change-Id: I42201d6e7b7ffe9ad4f19c774b638a36a51750ef --- .../ForegroundServiceLifetimeExtender.java | 15 +++- ...ForegroundServiceNotificationListener.java | 4 +- .../statusbar/NotificationClickNotifier.kt | 87 +++++++++++++++++++ .../NotificationInteractionTracker.kt | 40 +++++++++ ...NotificationLockscreenUserManagerImpl.java | 14 +-- .../NotificationRemoteInputManager.java | 9 +- .../statusbar/SmartReplyController.java | 13 ++- .../dagger/StatusBarDependenciesModule.java | 9 +- .../NotificationEntryListener.java | 2 +- .../notification/collection/ListDumper.java | 18 +++- .../collection/ShadeListBuilder.java | 7 +- .../NotifCollectionListener.java | 2 +- .../StatusBarNotificationActivityStarter.java | 22 ++--- .../ForegroundServiceControllerTest.java | 3 +- ...groundServiceNotificationListenerTest.java | 9 +- ...NotificationLockscreenUserManagerTest.java | 5 +- .../NotificationRemoteInputManagerTest.java | 4 + .../statusbar/SmartReplyControllerTest.java | 4 +- .../collection/ShadeListBuilderTest.java | 7 +- ...tusBarNotificationActivityStarterTest.java | 14 +-- 20 files changed, 224 insertions(+), 64 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java index e17d4e69093a8..77abffc82d68c 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java @@ -23,10 +23,13 @@ import android.os.Looper; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.statusbar.NotificationInteractionTracker; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.util.time.SystemClock; +import javax.inject.Inject; + /** * Extends the lifetime of foreground notification services such that they show for at least * five seconds @@ -41,9 +44,14 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx private ArraySet mManagedEntries = new ArraySet<>(); private Handler mHandler = new Handler(Looper.getMainLooper()); private final SystemClock mSystemClock; + private final NotificationInteractionTracker mInteractionTracker; - public ForegroundServiceLifetimeExtender(SystemClock systemClock) { + @Inject + public ForegroundServiceLifetimeExtender( + NotificationInteractionTracker interactionTracker, + SystemClock systemClock) { mSystemClock = systemClock; + mInteractionTracker = interactionTracker; } @Override @@ -58,8 +66,9 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx return false; } - long currentTime = mSystemClock.uptimeMillis(); - return currentTime - entry.getCreationTime() < MIN_FGS_TIME_MS; + boolean hasInteracted = mInteractionTracker.hasUserInteractedWith(entry.getKey()); + long aliveTime = mSystemClock.uptimeMillis() - entry.getCreationTime(); + return aliveTime < MIN_FGS_TIME_MS && !hasInteracted; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java index ef1f4e0afeded..650b9a7f9c0cd 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java @@ -51,6 +51,7 @@ public class ForegroundServiceNotificationListener { ForegroundServiceController foregroundServiceController, NotificationEntryManager notificationEntryManager, NotifPipeline notifPipeline, + ForegroundServiceLifetimeExtender fgsLifetimeExtender, SystemClock systemClock) { mContext = context; mForegroundServiceController = foregroundServiceController; @@ -78,8 +79,7 @@ public class ForegroundServiceNotificationListener { removeNotification(entry.getSbn()); } }); - mEntryManager.addNotificationLifetimeExtender( - new ForegroundServiceLifetimeExtender(systemClock)); + mEntryManager.addNotificationLifetimeExtender(fgsLifetimeExtender); notifPipeline.addCollectionListener(new NotifCollectionListener() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt new file mode 100644 index 0000000000000..8248fc9f5844b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt @@ -0,0 +1,87 @@ +package com.android.systemui.statusbar + +import android.app.Notification +import android.os.RemoteException +import com.android.internal.statusbar.IStatusBarService +import com.android.internal.statusbar.NotificationVisibility +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.util.Assert +import java.util.concurrent.Executor +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Class to shim calls to IStatusBarManager#onNotificationClick/#onNotificationActionClick that + * allow an in-process notification to go out (e.g., for tracking interactions) as well as + * sending the messages along to system server. + * + * NOTE: this class eats exceptions from system server, as no current client of these APIs cares + * about errors + */ +@Singleton +public class NotificationClickNotifier @Inject constructor( + val barService: IStatusBarService, + @Main val mainExecutor: Executor +) { + val listeners = mutableListOf() + + fun addNotificationInteractionListener(listener: NotificationInteractionListener) { + Assert.isMainThread() + listeners.add(listener) + } + + fun removeNotificationInteractionListener(listener: NotificationInteractionListener) { + Assert.isMainThread() + listeners.remove(listener) + } + + private fun notifyListenersAboutInteraction(key: String) { + for (l in listeners) { + l.onNotificationInteraction(key) + } + } + + fun onNotificationActionClick( + key: String, + actionIndex: Int, + action: Notification.Action, + visibility: NotificationVisibility, + generatedByAssistant: Boolean + ) { + try { + barService.onNotificationActionClick( + key, actionIndex, action, visibility, generatedByAssistant) + } catch (e: RemoteException) { + // nothing + } + + mainExecutor.execute { + notifyListenersAboutInteraction(key) + } + } + + fun onNotificationClick( + key: String, + visibility: NotificationVisibility + ) { + try { + barService.onNotificationClick(key, visibility) + } catch (e: RemoteException) { + // nothing + } + + mainExecutor.execute { + notifyListenersAboutInteraction(key) + } + } +} + +/** + * Interface for listeners to get notified when a notification is interacted with via a click or + * interaction with remote input or actions + */ +interface NotificationInteractionListener { + fun onNotificationInteraction(key: String) +} + +private const val TAG = "NotificationClickNotifier" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt new file mode 100644 index 0000000000000..2ed04eb088a3e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt @@ -0,0 +1,40 @@ +package com.android.systemui.statusbar + +import com.android.systemui.statusbar.notification.NotificationEntryManager +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Class to track user interaction with notifications. It's a glorified map of key : bool that can + * merge multiple "user interacted with notification" signals into a single place. + */ +@Singleton +class NotificationInteractionTracker @Inject constructor( + private val clicker: NotificationClickNotifier, + private val entryManager: NotificationEntryManager +) : NotifCollectionListener, NotificationInteractionListener { + private val interactions = mutableMapOf() + + init { + clicker.addNotificationInteractionListener(this) + entryManager.addCollectionListener(this) + } + + fun hasUserInteractedWith(key: String): Boolean = key in interactions + + override fun onEntryAdded(entry: NotificationEntry) { + interactions[entry.key] = false + } + + override fun onEntryCleanUp(entry: NotificationEntry) { + interactions.remove(entry.key) + } + + override fun onNotificationInteraction(key: String) { + interactions[key] = true + } +} + +private const val TAG = "NotificationInteractionTracker" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java index 2baab61d861b7..03424c4956ade 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java @@ -35,7 +35,6 @@ import android.content.IntentSender; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.os.Handler; -import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; @@ -43,7 +42,6 @@ import android.util.Log; import android.util.SparseArray; import android.util.SparseBooleanArray; -import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; @@ -92,9 +90,9 @@ public class NotificationLockscreenUserManagerImpl implements private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray(); private final UserManager mUserManager; - private final IStatusBarService mBarService; private final List mListeners = new ArrayList<>(); private final BroadcastDispatcher mBroadcastDispatcher; + private final NotificationClickNotifier mClickNotifier; private boolean mShowLockscreenNotifications; private boolean mAllowLockscreenRemoteInput; @@ -170,11 +168,7 @@ public class NotificationLockscreenUserManagerImpl implements final NotificationVisibility nv = NotificationVisibility.obtain( notificationKey, rank, count, true, location); - try { - mBarService.onNotificationClick(notificationKey, nv); - } catch (RemoteException exception) { - /* ignore */ - } + mClickNotifier.onNotificationClick(notificationKey, nv); } break; } @@ -203,7 +197,7 @@ public class NotificationLockscreenUserManagerImpl implements BroadcastDispatcher broadcastDispatcher, DevicePolicyManager devicePolicyManager, UserManager userManager, - IStatusBarService iStatusBarService, + NotificationClickNotifier clickNotifier, KeyguardManager keyguardManager, StatusBarStateController statusBarStateController, @Main Handler mainHandler, @@ -214,7 +208,7 @@ public class NotificationLockscreenUserManagerImpl implements mDevicePolicyManager = devicePolicyManager; mUserManager = userManager; mCurrentUserId = ActivityManager.getCurrentUser(); - mBarService = iStatusBarService; + mClickNotifier = clickNotifier; statusBarStateController.addCallback(this); mLockPatternUtils = new LockPatternUtils(context); mKeyguardManager = keyguardManager; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java index 9181c69e3722a..a81c7d35c9026 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java @@ -123,6 +123,7 @@ public class NotificationRemoteInputManager implements Dumpable { private final KeyguardManager mKeyguardManager; private final StatusBarStateController mStatusBarStateController; private final RemoteInputUriController mRemoteInputUriController; + private final NotificationClickNotifier mClickNotifier; protected RemoteInputController mRemoteInputController; protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback @@ -214,11 +215,7 @@ public class NotificationRemoteInputManager implements Dumpable { mEntryManager.getActiveNotificationUnfiltered(key)); final NotificationVisibility nv = NotificationVisibility.obtain(key, rank, count, true, location); - try { - mBarService.onNotificationActionClick(key, buttonIndex, action, nv, false); - } catch (RemoteException e) { - // Ignore - } + mClickNotifier.onNotificationActionClick(key, buttonIndex, action, nv, false); } private NotificationEntry getNotificationForParent(ViewParent parent) { @@ -275,6 +272,7 @@ public class NotificationRemoteInputManager implements Dumpable { StatusBarStateController statusBarStateController, @Main Handler mainHandler, RemoteInputUriController remoteInputUriController, + NotificationClickNotifier clickNotifier, ActionClickLogger logger) { mContext = context; mLockscreenUserManager = lockscreenUserManager; @@ -290,6 +288,7 @@ public class NotificationRemoteInputManager implements Dumpable { mKeyguardManager = context.getSystemService(KeyguardManager.class); mStatusBarStateController = statusBarStateController; mRemoteInputUriController = remoteInputUriController; + mClickNotifier = clickNotifier; notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java index bb96f42758e6e..7fc18b753d400 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java @@ -35,6 +35,7 @@ import java.util.Set; public class SmartReplyController { private final IStatusBarService mBarService; private final NotificationEntryManager mEntryManager; + private final NotificationClickNotifier mClickNotifier; private Set mSendingKeys = new ArraySet<>(); private Callback mCallback; @@ -42,9 +43,11 @@ public class SmartReplyController { * Injected constructor. See {@link StatusBarModule}. */ public SmartReplyController(NotificationEntryManager entryManager, - IStatusBarService statusBarService) { + IStatusBarService statusBarService, + NotificationClickNotifier clickNotifier) { mBarService = statusBarService; mEntryManager = entryManager; + mClickNotifier = clickNotifier; } public void setCallback(Callback callback) { @@ -78,12 +81,8 @@ public class SmartReplyController { NotificationLogger.getNotificationLocation(entry); final NotificationVisibility nv = NotificationVisibility.obtain( entry.getKey(), rank, count, true, location); - try { - mBarService.onNotificationActionClick( - entry.getKey(), actionIndex, action, nv, generatedByAssistant); - } catch (RemoteException e) { - // Nothing to do, system going down - } + mClickNotifier.onNotificationActionClick( + entry.getKey(), actionIndex, action, nv, generatedByAssistant); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java index b08eb9fafe41a..176e42667ab58 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java @@ -28,6 +28,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.ActionClickLogger; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.MediaArtworkProcessor; +import com.android.systemui.statusbar.NotificationClickNotifier; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationMediaManager; @@ -75,6 +76,7 @@ public interface StatusBarDependenciesModule { StatusBarStateController statusBarStateController, Handler mainHandler, RemoteInputUriController remoteInputUriController, + NotificationClickNotifier clickNotifier, ActionClickLogger actionClickLogger) { return new NotificationRemoteInputManager( context, @@ -85,6 +87,7 @@ public interface StatusBarDependenciesModule { statusBarStateController, mainHandler, remoteInputUriController, + clickNotifier, actionClickLogger); } @@ -128,8 +131,10 @@ public interface StatusBarDependenciesModule { @Singleton @Provides static SmartReplyController provideSmartReplyController( - NotificationEntryManager entryManager, IStatusBarService statusBarService) { - return new SmartReplyController(entryManager, statusBarService); + NotificationEntryManager entryManager, + IStatusBarService statusBarService, + NotificationClickNotifier clickNotifier) { + return new SmartReplyController(entryManager, statusBarService, clickNotifier); } /** */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java index 2beceb2c5e0ab..97ae83ef3f6a9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java @@ -90,7 +90,7 @@ public interface NotificationEntryListener { * @param removedByUser true if the notification was removed by a user action */ default void onEntryRemoved( - NotificationEntry entry, + @NonNull NotificationEntry entry, @Nullable NotificationVisibility visibility, boolean removedByUser, int reason) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java index 0caf0dc4a3a3f..97c1523887adc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification.collection; import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED; import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED; +import com.android.systemui.statusbar.NotificationInteractionTracker; + import java.util.Arrays; import java.util.List; @@ -35,6 +37,7 @@ public class ListDumper { */ public static String dumpTree( List entries, + NotificationInteractionTracker interactionTracker, boolean includeRecordKeeping, String indent) { StringBuilder sb = new StringBuilder(); @@ -46,7 +49,8 @@ public class ListDumper { indent, sb, true, - includeRecordKeeping); + includeRecordKeeping, + interactionTracker.hasUserInteractedWith(entry.getKey())); if (entry instanceof GroupEntry) { GroupEntry ge = (GroupEntry) entry; List children = ge.getChildren(); @@ -56,7 +60,8 @@ public class ListDumper { childEntryIndent, sb, true, - includeRecordKeeping); + includeRecordKeeping, + interactionTracker.hasUserInteractedWith(entry.getKey())); } } } @@ -80,7 +85,8 @@ public class ListDumper { indent, sb, false, - includeRecordKeeping); + includeRecordKeeping, + false); } return sb.toString(); } @@ -91,7 +97,9 @@ public class ListDumper { String indent, StringBuilder sb, boolean includeParent, - boolean includeRecordKeeping) { + boolean includeRecordKeeping, + boolean hasBeenInteractedWith + ) { sb.append(indent) .append("[").append(index).append("] ") .append(entry.getKey()); @@ -157,6 +165,8 @@ public class ListDumper { .append(" "); } + rksb.append("interacted=").append(hasBeenInteractedWith ? "yes" : "no").append(" "); + String rkString = rksb.toString(); if (!rkString.isEmpty()) { sb.append("\n\t") diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java index 4cec383776b21..9d81d3563ebbd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java @@ -36,6 +36,7 @@ import androidx.annotation.NonNull; import com.android.systemui.Dumpable; import com.android.systemui.dump.DumpManager; +import com.android.systemui.statusbar.NotificationInteractionTracker; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener; @@ -73,6 +74,7 @@ import javax.inject.Singleton; public class ShadeListBuilder implements Dumpable { private final SystemClock mSystemClock; private final ShadeListBuilderLogger mLogger; + private final NotificationInteractionTracker mInteractionTracker; private List mNotifList = new ArrayList<>(); private List mNewNotifList = new ArrayList<>(); @@ -105,10 +107,12 @@ public class ShadeListBuilder implements Dumpable { public ShadeListBuilder( SystemClock systemClock, ShadeListBuilderLogger logger, - DumpManager dumpManager) { + DumpManager dumpManager, + NotificationInteractionTracker interactionTracker) { Assert.isMainThread(); mSystemClock = systemClock; mLogger = logger; + mInteractionTracker = interactionTracker; dumpManager.registerDumpable(TAG, this); } @@ -821,6 +825,7 @@ public class ShadeListBuilder implements Dumpable { pw.println(ListDumper.dumpTree( getShadeList(), + mInteractionTracker, true, "\t\t")); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java index 3fab6f7c38573..75d772e8a1c51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java @@ -77,7 +77,7 @@ public interface NotifCollectionListener { * the entry during this call. Instead, use {@link #onEntryRemoved} which will be called before * deletion. */ - default void onEntryCleanUp(NotificationEntry entry) { + default void onEntryCleanUp(@NonNull NotificationEntry entry) { } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 7924348d34d4f..64e5f0a8184ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -45,7 +45,6 @@ import android.view.RemoteAnimationAdapter; import android.view.View; import com.android.internal.logging.MetricsLogger; -import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.ActivityIntentHelper; @@ -59,6 +58,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FeatureFlags; +import com.android.systemui.statusbar.NotificationClickNotifier; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -103,7 +103,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final NotifCollection mNotifCollection; private final HeadsUpManagerPhone mHeadsUpManager; private final ActivityStarter mActivityStarter; - private final IStatusBarService mBarService; + private final NotificationClickNotifier mClickNotifier; private final StatusBarStateController mStatusBarStateController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardManager mKeyguardManager; @@ -142,7 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit NotifCollection notifCollection, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, - IStatusBarService statusBarService, + NotificationClickNotifier clickNotifier, StatusBarStateController statusBarStateController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, KeyguardManager keyguardManager, @@ -177,7 +177,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mNotifCollection = notifCollection; mHeadsUpManager = headsUpManager; mActivityStarter = activityStarter; - mBarService = statusBarService; + mClickNotifier = clickNotifier; mStatusBarStateController = statusBarStateController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardManager = keyguardManager; @@ -379,11 +379,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit NotificationLogger.getNotificationLocation(entry); final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey, rank, count, true, location); - try { - mBarService.onNotificationClick(notificationKey, nv); - } catch (RemoteException ex) { - // system process is dead if we're here. - } + mClickNotifier.onNotificationClick(notificationKey, nv); if (!isBubble) { if (parentToCancelFinal != null) { @@ -651,7 +647,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final NotifCollection mNotifCollection; private final HeadsUpManagerPhone mHeadsUpManager; private final ActivityStarter mActivityStarter; - private final IStatusBarService mStatusBarService; + private final NotificationClickNotifier mClickNotifier; private final StatusBarStateController mStatusBarStateController; private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; private final KeyguardManager mKeyguardManager; @@ -689,7 +685,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit NotifCollection notifCollection, HeadsUpManagerPhone headsUpManager, ActivityStarter activityStarter, - IStatusBarService statusBarService, + NotificationClickNotifier clickNotifier, StatusBarStateController statusBarStateController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, KeyguardManager keyguardManager, @@ -720,7 +716,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mNotifCollection = notifCollection; mHeadsUpManager = headsUpManager; mActivityStarter = activityStarter; - mStatusBarService = statusBarService; + mClickNotifier = clickNotifier; mStatusBarStateController = statusBarStateController; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; mKeyguardManager = keyguardManager; @@ -777,7 +773,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mNotifCollection, mHeadsUpManager, mActivityStarter, - mStatusBarService, + mClickNotifier, mStatusBarStateController, mStatusBarKeyguardViewManager, mKeyguardManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index 45f9437efc15b..805254cda1757 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -85,7 +85,8 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { mFsc = new ForegroundServiceController( mEntryManager, mAppOpsController, mMainHandler); mListener = new ForegroundServiceNotificationListener( - mContext, mFsc, mEntryManager, mNotifPipeline, mClock); + mContext, mFsc, mEntryManager, mNotifPipeline, + mock(ForegroundServiceLifetimeExtender.class), mClock); ArgumentCaptor entryListenerCaptor = ArgumentCaptor.forClass(NotificationEntryListener.class); verify(mEntryManager).addNotificationEntryListener( diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java index bca8deeafd340..050b5538773d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceNotificationListenerTest.java @@ -26,6 +26,7 @@ import android.app.Notification; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.systemui.statusbar.NotificationInteractionTracker; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.util.time.FakeSystemClock; @@ -33,6 +34,8 @@ import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @RunWith(AndroidJUnit4.class) @SmallTest @@ -42,9 +45,13 @@ public class ForegroundServiceNotificationListenerTest extends SysuiTestCase { private Notification mNotif; private final FakeSystemClock mClock = new FakeSystemClock(); + @Mock + private NotificationInteractionTracker mInteractionTracker; + @Before public void setup() { - mExtender = new ForegroundServiceLifetimeExtender(mClock); + MockitoAnnotations.initMocks(this); + mExtender = new ForegroundServiceLifetimeExtender(mInteractionTracker, mClock); mNotif = new Notification.Builder(mContext, "") .setSmallIcon(R.drawable.ic_person) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java index a24fa842eca7b..808f17b8ba70d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java @@ -52,7 +52,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; -import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.Dependency; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -86,7 +85,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { @Mock private DevicePolicyManager mDevicePolicyManager; @Mock - private IStatusBarService mIStatusBarService; + private NotificationClickNotifier mClickNotifier; @Mock private KeyguardManager mKeyguardManager; @Mock @@ -397,7 +396,7 @@ public class NotificationLockscreenUserManagerTest extends SysuiTestCase { extends NotificationLockscreenUserManagerImpl { public TestNotificationLockscreenUserManager(Context context) { super(context, mBroadcastDispatcher, mDevicePolicyManager, mUserManager, - mIStatusBarService, NotificationLockscreenUserManagerTest.this.mKeyguardManager, + mClickNotifier, NotificationLockscreenUserManagerTest.this.mKeyguardManager, mStatusBarStateController, Handler.createAsync(Looper.myLooper()), mDeviceProvisionedController, mKeyguardStateController); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java index 5a7dea4de29ce..eaef43d133af2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java @@ -62,6 +62,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { @Mock private ExpandableNotificationRow mRow; @Mock private StatusBarStateController mStateController; @Mock private RemoteInputUriController mRemoteInputUriController; + @Mock private NotificationClickNotifier mClickNotifier; // Dependency mocks: @Mock private NotificationEntryManager mEntryManager; @@ -83,6 +84,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { mStateController, Handler.createAsync(Looper.myLooper()), mRemoteInputUriController, + mClickNotifier, mock(ActionClickLogger.class)); mEntry = new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_NAME) @@ -266,6 +268,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { StatusBarStateController statusBarStateController, Handler mainHandler, RemoteInputUriController remoteInputUriController, + NotificationClickNotifier clickNotifier, ActionClickLogger actionClickLogger) { super( context, @@ -276,6 +279,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase { statusBarStateController, mainHandler, remoteInputUriController, + clickNotifier, actionClickLogger); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java index 79507e96ae02d..7cbc4e4e2c621 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java @@ -75,6 +75,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { @Mock private IStatusBarService mIStatusBarService; @Mock private StatusBarStateController mStatusBarStateController; @Mock private RemoteInputUriController mRemoteInputUriController; + @Mock private NotificationClickNotifier mClickNotifier; @Before public void setUp() { @@ -83,7 +84,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { mNotificationEntryManager); mSmartReplyController = new SmartReplyController(mNotificationEntryManager, - mIStatusBarService); + mIStatusBarService, mClickNotifier); mDependency.injectTestDependency(SmartReplyController.class, mSmartReplyController); @@ -93,6 +94,7 @@ public class SmartReplyControllerTest extends SysuiTestCase { mStatusBarStateController, Handler.createAsync(Looper.myLooper()), mRemoteInputUriController, + mClickNotifier, mock(ActionClickLogger.class)); mRemoteInputManager.setUpWithCallback(mCallback, mDelegate); mNotification = new Notification.Builder(mContext, "") diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java index a93b54ac10098..6fa5055c875d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java @@ -44,6 +44,7 @@ import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; +import com.android.systemui.statusbar.NotificationInteractionTracker; import com.android.systemui.statusbar.notification.collection.ShadeListBuilder.OnRenderListListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener; import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener; @@ -86,6 +87,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { @Mock private ShadeListBuilderLogger mLogger; @Mock private NotifCollection mNotifCollection; + @Mock private NotificationInteractionTracker mInteractionTracker; @Spy private OnBeforeTransformGroupsListener mOnBeforeTransformGroupsListener; @Spy private OnBeforeSortListener mOnBeforeSortListener; @Spy private OnBeforeFinalizeFilterListener mOnBeforeFinalizeFilterListener; @@ -107,7 +109,8 @@ public class ShadeListBuilderTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); allowTestableLooperAsMainThread(); - mListBuilder = new ShadeListBuilder(mSystemClock, mLogger, mock(DumpManager.class)); + mListBuilder = new ShadeListBuilder( + mSystemClock, mLogger, mock(DumpManager.class), mInteractionTracker); mListBuilder.setOnRenderListListener(mOnRenderListListener); mListBuilder.attach(mNotifCollection); @@ -1280,7 +1283,7 @@ public class ShadeListBuilderTest extends SysuiTestCase { } catch (AssertionError err) { throw new AssertionError( "List under test failed verification:\n" + dumpTree(mBuiltList, - true, ""), err); + mInteractionTracker, true, ""), err); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 1afe132f00a97..53a1773b1bd18 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -48,7 +48,6 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; -import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.ActivityIntentHelper; @@ -59,6 +58,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.FeatureFlags; +import com.android.systemui.statusbar.NotificationClickNotifier; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoteInputManager; @@ -98,7 +98,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { @Mock private ActivityStarter mActivityStarter; @Mock - private IStatusBarService mStatusBarService; + private NotificationClickNotifier mClickNotifier; @Mock private StatusBarStateController mStatusBarStateController; @Mock @@ -188,7 +188,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotifCollection, mock(HeadsUpManagerPhone.class), mActivityStarter, - mStatusBarService, + mClickNotifier, mock(StatusBarStateController.class), mStatusBarKeyguardViewManager, mock(KeyguardManager.class), @@ -263,7 +263,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { verify(mAssistManager).hideAssist(); - verify(mStatusBarService).onNotificationClick( + verify(mClickNotifier).onNotificationClick( eq(sbn.getKey()), any(NotificationVisibility.class)); // Notification is removed due to FLAG_AUTO_CANCEL @@ -289,7 +289,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { verify(mAssistManager).hideAssist(); - verify(mStatusBarService).onNotificationClick( + verify(mClickNotifier).onNotificationClick( eq(sbn.getKey()), any(NotificationVisibility.class)); // The content intent should NOT be sent on click. @@ -319,7 +319,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { verify(mAssistManager).hideAssist(); - verify(mStatusBarService).onNotificationClick( + verify(mClickNotifier).onNotificationClick( eq(sbn.getKey()), any(NotificationVisibility.class)); // The content intent should NOT be sent on click. @@ -349,7 +349,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { verify(mAssistManager).hideAssist(); - verify(mStatusBarService).onNotificationClick( + verify(mClickNotifier).onNotificationClick( eq(sbn.getKey()), any(NotificationVisibility.class)); // The content intent should NOT be sent on click.