Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.RemoteInputView; import com.android.systemui.util.DumpUtilsKt; import com.android.systemui.util.ListenerSet; import java.io.PrintWriter; import java.util.ArrayList; Loading @@ -75,6 +76,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import dagger.Lazy; Loading Loading @@ -118,6 +120,8 @@ public class NotificationRemoteInputManager implements Dumpable { protected Callback mCallback; private final List<RemoteInputController.Callback> mControllerCallbacks = new ArrayList<>(); private final ListenerSet<Consumer<NotificationEntry>> mActionPressListeners = new ListenerSet<>(); private final InteractionHandler mInteractionHandler = new InteractionHandler() { Loading Loading @@ -401,6 +405,14 @@ public class NotificationRemoteInputManager implements Dumpable { } } public void addActionPressListener(Consumer<NotificationEntry> listener) { mActionPressListeners.addIfAbsent(listener); } public void removeActionPressListener(Consumer<NotificationEntry> listener) { mActionPressListeners.remove(listener); } /** * Activates a given {@link RemoteInput} * Loading Loading @@ -634,6 +646,9 @@ public class NotificationRemoteInputManager implements Dumpable { if (mRemoteInputListener != null) { mRemoteInputListener.releaseNotificationIfKeptForRemoteInputHistory(entry); } for (Consumer<NotificationEntry> listener : mActionPressListeners) { listener.accept(entry); } } /** Returns whether the notification should be lifetime extended for smart reply history */ Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt +10 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.collection.coordinator import android.app.Notification import android.app.Notification.GROUP_ALERT_SUMMARY import android.util.ArrayMap import android.util.ArraySet import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.NotificationRemoteInputManager import com.android.systemui.statusbar.notification.collection.GroupEntry Loading @@ -41,6 +40,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.time.SystemClock import java.util.function.Consumer import javax.inject.Inject /** Loading Loading @@ -85,6 +85,7 @@ class HeadsUpCoordinator @Inject constructor( pipeline.addOnBeforeFinalizeFilterListener(::onBeforeFinalizeFilter) pipeline.addPromoter(mNotifPromoter) pipeline.addNotificationLifetimeExtender(mLifetimeExtender) mRemoteInputManager.addActionPressListener(mActionPressListener) } private fun onHeadsUpViewBound(entry: NotificationEntry) { Loading Loading @@ -448,6 +449,14 @@ class HeadsUpCoordinator @Inject constructor( (entry.sbn.notification.flags and Notification.FLAG_ONLY_ALERT_ONCE) == 0) } /** When an action is pressed on a notification, end HeadsUp lifetime extension. */ private val mActionPressListener = Consumer<NotificationEntry> { entry -> if (mNotifsExtendingLifetime.contains(entry)) { val removeInMillis = mHeadsUpManager.getEarliestRemovalTime(entry.key) mExecutor.executeDelayed({ endNotifLifetimeExtensionIfExtended(entry) }, removeInMillis) } } private val mLifetimeExtender = object : NotifLifetimeExtender { override fun getName() = TAG Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +18 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.util.ArrayList import java.util.function.Consumer import org.mockito.Mockito.`when` as whenever @SmallTest Loading @@ -75,6 +76,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { private lateinit var mBeforeFinalizeFilterListener: OnBeforeFinalizeFilterListener private lateinit var mOnHeadsUpChangedListener: OnHeadsUpChangedListener private lateinit var mNotifSectioner: NotifSectioner private lateinit var mActionPressListener: Consumer<NotificationEntry> private val mNotifPipeline: NotifPipeline = mock() private val mLogger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true) Loading Loading @@ -131,6 +133,9 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { mOnHeadsUpChangedListener = withArgCaptor { verify(mHeadsUpManager).addListener(capture()) } mActionPressListener = withArgCaptor { verify(mRemoteInputManager).addActionPressListener(capture()) } given(mHeadsUpManager.allEntries).willAnswer { mHuns.stream() } given(mHeadsUpManager.isAlerting(anyString())).willAnswer { invocation -> val key = invocation.getArgument<String>(0) Loading Loading @@ -198,6 +203,19 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { verify(mHeadsUpManager, times(0)).removeNotification(anyString(), any()) } @Test fun hunExtensionCancelledWhenHunActionPressed() { whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true) addHUN(mEntry) whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false) whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L) assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0)) mActionPressListener.accept(mEntry) mExecutor.advanceClockToLast() mExecutor.runAllReady() verify(mHeadsUpManager, times(1)).removeNotification(eq(mEntry.key), eq(true)) } @Test fun testCancelUpdatedStickyNotification() { whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true) Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.RemoteInputUriController; import com.android.systemui.statusbar.policy.RemoteInputView; import com.android.systemui.util.DumpUtilsKt; import com.android.systemui.util.ListenerSet; import java.io.PrintWriter; import java.util.ArrayList; Loading @@ -75,6 +76,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import dagger.Lazy; Loading Loading @@ -118,6 +120,8 @@ public class NotificationRemoteInputManager implements Dumpable { protected Callback mCallback; private final List<RemoteInputController.Callback> mControllerCallbacks = new ArrayList<>(); private final ListenerSet<Consumer<NotificationEntry>> mActionPressListeners = new ListenerSet<>(); private final InteractionHandler mInteractionHandler = new InteractionHandler() { Loading Loading @@ -401,6 +405,14 @@ public class NotificationRemoteInputManager implements Dumpable { } } public void addActionPressListener(Consumer<NotificationEntry> listener) { mActionPressListeners.addIfAbsent(listener); } public void removeActionPressListener(Consumer<NotificationEntry> listener) { mActionPressListeners.remove(listener); } /** * Activates a given {@link RemoteInput} * Loading Loading @@ -634,6 +646,9 @@ public class NotificationRemoteInputManager implements Dumpable { if (mRemoteInputListener != null) { mRemoteInputListener.releaseNotificationIfKeptForRemoteInputHistory(entry); } for (Consumer<NotificationEntry> listener : mActionPressListeners) { listener.accept(entry); } } /** Returns whether the notification should be lifetime extended for smart reply history */ Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt +10 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.systemui.statusbar.notification.collection.coordinator import android.app.Notification import android.app.Notification.GROUP_ALERT_SUMMARY import android.util.ArrayMap import android.util.ArraySet import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.NotificationRemoteInputManager import com.android.systemui.statusbar.notification.collection.GroupEntry Loading @@ -41,6 +40,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.time.SystemClock import java.util.function.Consumer import javax.inject.Inject /** Loading Loading @@ -85,6 +85,7 @@ class HeadsUpCoordinator @Inject constructor( pipeline.addOnBeforeFinalizeFilterListener(::onBeforeFinalizeFilter) pipeline.addPromoter(mNotifPromoter) pipeline.addNotificationLifetimeExtender(mLifetimeExtender) mRemoteInputManager.addActionPressListener(mActionPressListener) } private fun onHeadsUpViewBound(entry: NotificationEntry) { Loading Loading @@ -448,6 +449,14 @@ class HeadsUpCoordinator @Inject constructor( (entry.sbn.notification.flags and Notification.FLAG_ONLY_ALERT_ONCE) == 0) } /** When an action is pressed on a notification, end HeadsUp lifetime extension. */ private val mActionPressListener = Consumer<NotificationEntry> { entry -> if (mNotifsExtendingLifetime.contains(entry)) { val removeInMillis = mHeadsUpManager.getEarliestRemovalTime(entry.key) mExecutor.executeDelayed({ endNotifLifetimeExtensionIfExtended(entry) }, removeInMillis) } } private val mLifetimeExtender = object : NotifLifetimeExtender { override fun getName() = TAG Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +18 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import org.mockito.Mockito.times import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations import java.util.ArrayList import java.util.function.Consumer import org.mockito.Mockito.`when` as whenever @SmallTest Loading @@ -75,6 +76,7 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { private lateinit var mBeforeFinalizeFilterListener: OnBeforeFinalizeFilterListener private lateinit var mOnHeadsUpChangedListener: OnHeadsUpChangedListener private lateinit var mNotifSectioner: NotifSectioner private lateinit var mActionPressListener: Consumer<NotificationEntry> private val mNotifPipeline: NotifPipeline = mock() private val mLogger = HeadsUpCoordinatorLogger(logcatLogBuffer(), verbose = true) Loading Loading @@ -131,6 +133,9 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { mOnHeadsUpChangedListener = withArgCaptor { verify(mHeadsUpManager).addListener(capture()) } mActionPressListener = withArgCaptor { verify(mRemoteInputManager).addActionPressListener(capture()) } given(mHeadsUpManager.allEntries).willAnswer { mHuns.stream() } given(mHeadsUpManager.isAlerting(anyString())).willAnswer { invocation -> val key = invocation.getArgument<String>(0) Loading Loading @@ -198,6 +203,19 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { verify(mHeadsUpManager, times(0)).removeNotification(anyString(), any()) } @Test fun hunExtensionCancelledWhenHunActionPressed() { whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true) addHUN(mEntry) whenever(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false) whenever(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L) assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0)) mActionPressListener.accept(mEntry) mExecutor.advanceClockToLast() mExecutor.runAllReady() verify(mHeadsUpManager, times(1)).removeNotification(eq(mEntry.key), eq(true)) } @Test fun testCancelUpdatedStickyNotification() { whenever(mHeadsUpManager.isSticky(anyString())).thenReturn(true) Loading