summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt95
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt128
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEvents.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEventsModule.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java85
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt138
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java49
19 files changed, 579 insertions, 203 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt
new file mode 100644
index 000000000000..b54163d29e80
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinator.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender.OnEndLifetimeExtensionCallback
+import com.android.systemui.statusbar.phone.NotifActivityLaunchEvents
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+
+/** Extends the lifetime of notifications while their activity launch animation is playing. */
+interface ActivityLaunchAnimCoordinator : Coordinator
+
+/** Provides an [ActivityLaunchAnimCoordinator] to [CoordinatorScope]. */
+@Module(includes = [PrivateActivityStarterCoordinatorModule::class])
+object ActivityLaunchAnimCoordinatorModule
+
+@Module
+private interface PrivateActivityStarterCoordinatorModule {
+ @Binds
+ fun bindCoordinator(impl: ActivityLaunchAnimCoordinatorImpl): ActivityLaunchAnimCoordinator
+}
+
+/**
+ * Listens for [NotifActivityLaunchEvents], and then extends the lifetimes of any notifs while their
+ * launch animation is playing.
+ */
+@CoordinatorScope
+private class ActivityLaunchAnimCoordinatorImpl @Inject constructor(
+ private val activityLaunchEvents: NotifActivityLaunchEvents
+) : ActivityLaunchAnimCoordinator {
+ // Tracks notification launches, and whether or not their lifetimes are extended.
+ private val notifsLaunchingActivities = mutableMapOf<String, Boolean>()
+
+ private var onEndLifetimeExtensionCallback: OnEndLifetimeExtensionCallback? = null
+
+ override fun attach(pipeline: NotifPipeline) {
+ activityLaunchEvents.registerListener(activityStartEventListener)
+ pipeline.addNotificationLifetimeExtender(extender)
+ }
+
+ private val activityStartEventListener = object : NotifActivityLaunchEvents.Listener {
+ override fun onStartLaunchNotifActivity(entry: NotificationEntry) {
+ notifsLaunchingActivities[entry.key] = false
+ }
+
+ override fun onFinishLaunchNotifActivity(entry: NotificationEntry) {
+ if (notifsLaunchingActivities.remove(entry.key) == true) {
+ // If we were extending the lifetime of this notification, stop.
+ onEndLifetimeExtensionCallback?.onEndLifetimeExtension(extender, entry)
+ }
+ }
+ }
+
+ private val extender = object : NotifLifetimeExtender {
+ override fun getName(): String = "ActivityStarterCoordinator"
+
+ override fun setCallback(callback: OnEndLifetimeExtensionCallback) {
+ onEndLifetimeExtensionCallback = callback
+ }
+
+ override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
+ if (entry.key in notifsLaunchingActivities) {
+ // Track that we're now extending this notif
+ notifsLaunchingActivities[entry.key] = true
+ return true
+ }
+ return false
+ }
+
+ override fun cancelLifetimeExtension(entry: NotificationEntry) {
+ if (entry.key in notifsLaunchingActivities) {
+ notifsLaunchingActivities[entry.key] = false
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 757fb5a2fe9a..be20df460bb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -58,7 +58,8 @@ class NotifCoordinatorsImpl @Inject constructor(
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
viewConfigCoordinator: ViewConfigCoordinator,
visualStabilityCoordinator: VisualStabilityCoordinator,
- sensitiveContentCoordinator: SensitiveContentCoordinator
+ sensitiveContentCoordinator: SensitiveContentCoordinator,
+ activityLaunchAnimCoordinator: ActivityLaunchAnimCoordinator
) : NotifCoordinators {
private val mCoordinators: MutableList<Coordinator> = ArrayList()
@@ -97,6 +98,7 @@ class NotifCoordinatorsImpl @Inject constructor(
mCoordinators.add(viewConfigCoordinator)
mCoordinators.add(visualStabilityCoordinator)
mCoordinators.add(sensitiveContentCoordinator)
+ mCoordinators.add(activityLaunchAnimCoordinator)
if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
mCoordinators.add(smartspaceDedupingCoordinator)
}
@@ -144,4 +146,4 @@ class NotifCoordinatorsImpl @Inject constructor(
companion object {
private const val TAG = "NotifCoordinators"
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
index 72d091883ce6..3f8a39f62dfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
@@ -34,11 +34,11 @@ import dagger.Binds
import dagger.Module
import javax.inject.Inject
-@Module(includes = [PrivateModule::class])
+@Module(includes = [PrivateSensitiveContentCoordinatorModule::class])
interface SensitiveContentCoordinatorModule
@Module
-private interface PrivateModule {
+private interface PrivateSensitiveContentCoordinatorModule {
@Binds
fun bindCoordinator(impl: SensitiveContentCoordinatorImpl): SensitiveContentCoordinator
}
@@ -121,4 +121,4 @@ private fun extractAllRepresentativeEntries(listEntry: ListEntry): Sequence<Noti
if (listEntry is GroupEntry) {
yieldAll(extractAllRepresentativeEntries(listEntry.children))
}
- } \ No newline at end of file
+ }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 3aa3549a7c27..699c4e77321e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -32,7 +32,7 @@ import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSource;
+import com.android.systemui.statusbar.phone.NotifPanelEvents;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -53,10 +53,10 @@ import javax.inject.Inject;
// TODO(b/204468557): Move to @CoordinatorScope
@SysUISingleton
public class VisualStabilityCoordinator implements Coordinator, Dumpable,
- NotifPanelEventSource.Callbacks {
+ NotifPanelEvents.Listener {
private final DelayableExecutor mDelayableExecutor;
private final HeadsUpManager mHeadsUpManager;
- private final NotifPanelEventSource mNotifPanelEventSource;
+ private final NotifPanelEvents mNotifPanelEvents;
private final StatusBarStateController mStatusBarStateController;
private final VisualStabilityProvider mVisualStabilityProvider;
private final WakefulnessLifecycle mWakefulnessLifecycle;
@@ -87,7 +87,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
DelayableExecutor delayableExecutor,
DumpManager dumpManager,
HeadsUpManager headsUpManager,
- NotifPanelEventSource notifPanelEventSource,
+ NotifPanelEvents notifPanelEvents,
StatusBarStateController statusBarStateController,
VisualStabilityProvider visualStabilityProvider,
WakefulnessLifecycle wakefulnessLifecycle) {
@@ -96,7 +96,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
mWakefulnessLifecycle = wakefulnessLifecycle;
mStatusBarStateController = statusBarStateController;
mDelayableExecutor = delayableExecutor;
- mNotifPanelEventSource = notifPanelEventSource;
+ mNotifPanelEvents = notifPanelEvents;
dumpManager.registerDumpable(this);
}
@@ -109,7 +109,7 @@ public class VisualStabilityCoordinator implements Coordinator, Dumpable,
mStatusBarStateController.addCallback(mStatusBarStateControllerListener);
mPulsing = mStatusBarStateController.isPulsing();
- mNotifPanelEventSource.registerCallbacks(this);
+ mNotifPanelEvents.registerListener(this);
pipeline.setVisualStabilityManager(mNotifStabilityManager);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
index a26d50d2a059..274affd9da43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.coordinator.dagger
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.collection.coordinator.ActivityLaunchAnimCoordinatorModule
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinatorsImpl
import com.android.systemui.statusbar.notification.collection.coordinator.SensitiveContentCoordinatorModule
@@ -47,7 +48,10 @@ interface CoordinatorsSubcomponent {
}
}
-@Module(includes = [SensitiveContentCoordinatorModule::class])
+@Module(includes = [
+ ActivityLaunchAnimCoordinatorModule::class,
+ SensitiveContentCoordinatorModule::class,
+])
private abstract class InternalCoordinatorsModule {
@Binds
@Internal
@@ -62,4 +66,4 @@ private annotation class Internal
@Scope
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
-annotation class CoordinatorScope \ No newline at end of file
+annotation class CoordinatorScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt
deleted file mode 100644
index 470737e3b772..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifPanelEventSource.kt
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.statusbar.notification.collection.render
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.phone.NotificationPanelViewController
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
-import com.android.systemui.util.ListenerSet
-import dagger.Binds
-import dagger.Module
-import dagger.Provides
-import dagger.multibindings.IntoSet
-
-/** Provides certain notification panel events. */
-interface NotifPanelEventSource {
-
- /** Registers callbacks to be invoked when notification panel events occur. */
- fun registerCallbacks(callbacks: Callbacks)
-
- /** Unregisters callbacks previously registered via [.registerCallbacks] */
- fun unregisterCallbacks(callbacks: Callbacks)
-
- /** Callbacks for certain notification panel events. */
- interface Callbacks {
-
- /** Invoked when the notification panel starts or stops collapsing. */
- fun onPanelCollapsingChanged(isCollapsing: Boolean)
-
- /**
- * Invoked when the notification panel starts or stops launching an [android.app.Activity].
- */
- fun onLaunchingActivityChanged(isLaunchingActivity: Boolean)
- }
-}
-
-@Module
-abstract class NotifPanelEventSourceModule {
-
- @Binds
- @SysUISingleton
- abstract fun bindEventSource(manager: NotifPanelEventSourceManager): NotifPanelEventSource
-
- @Module
- companion object {
- @JvmStatic
- @Provides
- fun provideManager(): NotifPanelEventSourceManager = NotifPanelEventSourceManagerImpl()
- }
-}
-
-@Module
-object StatusBarNotifPanelEventSourceModule {
- @JvmStatic
- @Provides
- @IntoSet
- @CentralSurfacesScope
- fun bindStartable(
- manager: NotifPanelEventSourceManager,
- notifPanelController: NotificationPanelViewController
- ): CentralSurfacesComponent.Startable =
- EventSourceStatusBarStartableImpl(manager, notifPanelController)
-}
-
-/**
- * Management layer that bridges [SysUiSingleton] and [CentralSurfacesScope]. Necessary because code
- * that wants to listen to [NotifPanelEventSource] lives in [SysUiSingleton], but the events
- * themselves come from [NotificationPanelViewController] in [CentralSurfacesScope].
- */
-interface NotifPanelEventSourceManager : NotifPanelEventSource {
- var eventSource: NotifPanelEventSource?
-}
-
-private class NotifPanelEventSourceManagerImpl
- : NotifPanelEventSourceManager, NotifPanelEventSource.Callbacks {
-
- private val callbackSet = ListenerSet<NotifPanelEventSource.Callbacks>()
-
- override var eventSource: NotifPanelEventSource? = null
- set(value) {
- field?.unregisterCallbacks(this)
- value?.registerCallbacks(this)
- field = value
- }
-
- override fun registerCallbacks(callbacks: NotifPanelEventSource.Callbacks) {
- callbackSet.addIfAbsent(callbacks)
- }
-
- override fun unregisterCallbacks(callbacks: NotifPanelEventSource.Callbacks) {
- callbackSet.remove(callbacks)
- }
-
- override fun onPanelCollapsingChanged(isCollapsing: Boolean) {
- callbackSet.forEach { it.onPanelCollapsingChanged(isCollapsing) }
- }
-
- override fun onLaunchingActivityChanged(isLaunchingActivity: Boolean) {
- callbackSet.forEach { it.onLaunchingActivityChanged(isLaunchingActivity) }
- }
-}
-
-private class EventSourceStatusBarStartableImpl(
- private val manager: NotifPanelEventSourceManager,
- private val notifPanelController: NotificationPanelViewController
-) : CentralSurfacesComponent.Startable {
-
- override fun start() {
- manager.eventSource = notifPanelController
- }
-
- override fun stop() {
- manager.eventSource = null
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 51bbf1c80478..efe88e6d4f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -68,7 +68,6 @@ import com.android.systemui.statusbar.notification.collection.render.GroupExpans
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl;
import com.android.systemui.statusbar.notification.collection.render.NotifGutsViewManager;
-import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSourceModule;
import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
@@ -84,9 +83,11 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
+import com.android.systemui.statusbar.phone.NotifActivityLaunchEventsModule;
+import com.android.systemui.statusbar.phone.NotifPanelEventsModule;
import com.android.systemui.statusbar.phone.ShadeController;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.wmshell.BubblesManager;
@@ -106,8 +107,9 @@ import dagger.Provides;
*/
@Module(includes = {
CoordinatorsModule.class,
+ NotifActivityLaunchEventsModule.class,
NotifPipelineChoreographerModule.class,
- NotifPanelEventSourceModule.class,
+ NotifPanelEventsModule.class,
NotificationSectionHeadersModule.class,
})
public interface NotificationsModule {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt
new file mode 100644
index 000000000000..f46d07338206
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEvents.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+
+/** Provides events about [android.app.Activity] launches from Notifications. */
+interface NotifActivityLaunchEvents {
+
+ /** Registers a [Listener] to be invoked when notification activity launch events occur. */
+ fun registerListener(listener: Listener)
+
+ /** Unregisters a [Listener] previously registered via [registerListener] */
+ fun unregisterListener(listener: Listener)
+
+ /** Listener for events about [android.app.Activity] launches from Notifications. */
+ interface Listener {
+
+ /** Invoked when an activity has started launching from a notification. */
+ fun onStartLaunchNotifActivity(entry: NotificationEntry)
+
+ /** Invoked when an activity has finished launching. */
+ fun onFinishLaunchNotifActivity(entry: NotificationEntry)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java
new file mode 100644
index 000000000000..84ff538677b0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifActivityLaunchEventsModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.dagger.SysUISingleton;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Provides a {@link NotifActivityLaunchEvents} in {@link SysUISingleton} scope. */
+@Module
+public abstract class NotifActivityLaunchEventsModule {
+ @Binds
+ abstract NotifActivityLaunchEvents bindLaunchEvents(
+ StatusBarNotificationActivityStarter.LaunchEventsEmitter impl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEvents.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEvents.kt
new file mode 100644
index 000000000000..a385e22c1aff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEvents.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+/** Provides certain notification panel events. */
+interface NotifPanelEvents {
+
+ /** Registers callbacks to be invoked when notification panel events occur. */
+ fun registerListener(listener: Listener)
+
+ /** Unregisters callbacks previously registered via [registerListener] */
+ fun unregisterListener(listener: Listener)
+
+ /** Callbacks for certain notification panel events. */
+ interface Listener {
+
+ /** Invoked when the notification panel starts or stops collapsing. */
+ fun onPanelCollapsingChanged(isCollapsing: Boolean)
+
+ /**
+ * Invoked when the notification panel starts or stops launching an [android.app.Activity].
+ */
+ fun onLaunchingActivityChanged(isLaunchingActivity: Boolean)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEventsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEventsModule.java
new file mode 100644
index 000000000000..2aaf6a5f4391
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotifPanelEventsModule.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import com.android.systemui.dagger.SysUISingleton;
+
+import dagger.Binds;
+import dagger.Module;
+
+/** Provides a {@link NotifPanelEvents} in {@link SysUISingleton} scope. */
+@Module
+public abstract class NotifPanelEventsModule {
+ @Binds
+ abstract NotifPanelEvents bindPanelEvents(
+ NotificationPanelViewController.PanelEventsEmitter impl);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 61760fb8c78c..292932f93182 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -128,6 +128,7 @@ import com.android.systemui.communal.CommunalSourceMonitor;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.communal.dagger.CommunalViewComponent;
import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
@@ -176,7 +177,6 @@ import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSource;
import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -223,8 +223,7 @@ import javax.inject.Inject;
import javax.inject.Provider;
@CentralSurfacesComponent.CentralSurfacesScope
-public class NotificationPanelViewController extends PanelViewController
- implements NotifPanelEventSource {
+public class NotificationPanelViewController extends PanelViewController {
private static final boolean DEBUG = false;
@@ -335,6 +334,7 @@ public class NotificationPanelViewController extends PanelViewController
private final TapAgainViewController mTapAgainViewController;
private final SplitShadeHeaderController mSplitShadeHeaderController;
private final RecordingController mRecordingController;
+ private final PanelEventsEmitter mPanelEventsEmitter;
private boolean mShouldUseSplitNotificationShade;
// The bottom padding reserved for elements of the keyguard measuring notifications
private float mKeyguardNotificationBottomPadding;
@@ -664,8 +664,6 @@ public class NotificationPanelViewController extends PanelViewController
private Optional<NotificationPanelUnfoldAnimationController>
mNotificationPanelUnfoldAnimationController;
- private final ListenerSet<Callbacks> mNotifEventSourceCallbacks = new ListenerSet<>();
-
private final NotificationListContainer mNotificationListContainer;
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@@ -796,7 +794,8 @@ public class NotificationPanelViewController extends PanelViewController
QsFrameTranslateController qsFrameTranslateController,
SysUiState sysUiState,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
- NotificationListContainer notificationListContainer) {
+ NotificationListContainer notificationListContainer,
+ PanelEventsEmitter panelEventsEmitter) {
super(view,
falsingManager,
dozeLog,
@@ -868,6 +867,7 @@ public class NotificationPanelViewController extends PanelViewController
mSecureSettings = secureSettings;
mInteractionJankMonitor = interactionJankMonitor;
mSysUiState = sysUiState;
+ mPanelEventsEmitter = panelEventsEmitter;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -3460,9 +3460,7 @@ public class NotificationPanelViewController extends PanelViewController
boolean wasRunning = isLaunchTransitionRunning();
super.setIsLaunchAnimationRunning(running);
if (wasRunning != isLaunchTransitionRunning()) {
- for (Callbacks cb : mNotifEventSourceCallbacks) {
- cb.onLaunchingActivityChanged(running);
- }
+ mPanelEventsEmitter.notifyLaunchingActivityChanged(running);
}
}
@@ -3471,9 +3469,7 @@ public class NotificationPanelViewController extends PanelViewController
boolean wasClosing = isClosing();
super.setIsClosing(isClosing);
if (wasClosing != isClosing) {
- for (Callbacks cb : mNotifEventSourceCallbacks) {
- cb.onPanelCollapsingChanged(isClosing);
- }
+ mPanelEventsEmitter.notifyPanelCollapsingChanged(isClosing);
}
}
@@ -4375,16 +4371,6 @@ public class NotificationPanelViewController extends PanelViewController
.commitUpdate(mDisplayId);
}
- @Override
- public void registerCallbacks(Callbacks callbacks) {
- mNotifEventSourceCallbacks.addIfAbsent(callbacks);
- }
-
- @Override
- public void unregisterCallbacks(Callbacks callbacks) {
- mNotifEventSourceCallbacks.remove(callbacks);
- }
-
private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
@Override
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
@@ -5158,4 +5144,35 @@ public class NotificationPanelViewController extends PanelViewController
1.0f /* speedUpFactor */);
}
}
+
+ @SysUISingleton
+ static class PanelEventsEmitter implements NotifPanelEvents {
+
+ private final ListenerSet<Listener> mListeners = new ListenerSet<>();
+
+ @Inject
+ PanelEventsEmitter() {}
+
+ @Override
+ public void registerListener(@NonNull Listener listener) {
+ mListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void unregisterListener(@NonNull Listener listener) {
+ mListeners.remove(listener);
+ }
+
+ private void notifyLaunchingActivityChanged(boolean isLaunchingActivity) {
+ for (Listener cb : mListeners) {
+ cb.onLaunchingActivityChanged(isLaunchingActivity);
+ }
+ }
+
+ private void notifyPanelCollapsingChanged(boolean isCollapsing) {
+ for (NotifPanelEvents.Listener cb : mListeners) {
+ cb.onPanelCollapsingChanged(isCollapsing);
+ }
+ }
+ }
}
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 edbddbb3c3e7..108d98a129b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -41,6 +41,7 @@ import android.text.TextUtils;
import android.util.EventLog;
import android.view.View;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
@@ -51,6 +52,7 @@ import com.android.systemui.ActivityIntentHelper;
import com.android.systemui.EventLogTags;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
@@ -75,6 +77,7 @@ import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.ListenerSet;
import com.android.systemui.wmshell.BubblesManager;
import java.util.Optional;
@@ -128,6 +131,7 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
private final ActivityLaunchAnimator mActivityLaunchAnimator;
private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
private final OnUserInteractionCallback mOnUserInteractionCallback;
+ private final LaunchEventsEmitter mLaunchEventsEmitter;
private boolean mIsCollapsingToShowActivityOverLockscreen;
@@ -166,7 +170,8 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
NotificationPresenter presenter,
NotificationPanelViewController panel,
ActivityLaunchAnimator activityLaunchAnimator,
- NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) {
+ NotificationLaunchAnimatorControllerProvider notificationAnimationProvider,
+ LaunchEventsEmitter launchEventsEmitter) {
mContext = context;
mCommandQueue = commandQueue;
mMainThreadHandler = mainThreadHandler;
@@ -192,18 +197,17 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
mLockPatternUtils = lockPatternUtils;
mStatusBarRemoteInputCallback = remoteInputCallback;
mActivityIntentHelper = activityIntentHelper;
-
mNotifPipelineFlags = notifPipelineFlags;
mMetricsLogger = metricsLogger;
mLogger = logger;
mOnUserInteractionCallback = onUserInteractionCallback;
-
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mCentralSurfaces = centralSurfaces;
mPresenter = presenter;
mNotificationPanel = panel;
mActivityLaunchAnimator = activityLaunchAnimator;
mNotificationAnimationProvider = notificationAnimationProvider;
+ mLaunchEventsEmitter = launchEventsEmitter;
if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@@ -254,6 +258,8 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
return;
}
+ mLaunchEventsEmitter.notifyStartLaunchNotifActivity(entry);
+
boolean isActivityIntent = intent != null && intent.isActivity() && !isBubble;
final boolean willLaunchResolverActivity = isActivityIntent
&& mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
@@ -280,7 +286,9 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
postKeyguardAction.onDismiss();
} else {
mActivityStarter.dismissKeyguardThenExecute(
- postKeyguardAction, null /* cancel */, willLaunchResolverActivity);
+ postKeyguardAction,
+ () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry),
+ willLaunchResolverActivity);
}
}
@@ -380,24 +388,26 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
// inform NMS that the notification was clicked
mClickNotifier.onNotificationClick(notificationKey, nv);
- if (!canBubble) {
- if (shouldAutoCancel || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(
- notificationKey)) {
- // Immediately remove notification from visually showing.
- // We have to post the removal to the UI thread for synchronization.
- mMainThreadHandler.post(() -> {
- final Runnable removeNotification = () ->
- mOnUserInteractionCallback.onDismiss(
- entry, REASON_CLICK, summaryToRemove);
- if (mPresenter.isCollapsing()) {
- // To avoid lags we're only performing the remove
- // after the shade is collapsed
- mShadeController.addPostCollapseAction(removeNotification);
- } else {
- removeNotification.run();
- }
- });
- }
+ if (!canBubble && (shouldAutoCancel
+ || mRemoteInputManager.isNotificationKeptForRemoteInputHistory(notificationKey))) {
+ // Immediately remove notification from visually showing.
+ // We have to post the removal to the UI thread for synchronization.
+ mMainThreadHandler.post(() -> {
+ final Runnable removeNotification = () -> {
+ mOnUserInteractionCallback.onDismiss(entry, REASON_CLICK, summaryToRemove);
+ mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
+ };
+ if (mPresenter.isCollapsing()) {
+ // To avoid lags we're only performing the remove
+ // after the shade is collapsed
+ mShadeController.addPostCollapseAction(removeNotification);
+ } else {
+ removeNotification.run();
+ }
+ });
+ } else {
+ mMainThreadHandler.post(
+ () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
}
mIsCollapsingToShowActivityOverLockscreen = false;
@@ -659,4 +669,35 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
return entry.shouldSuppressFullScreenIntent();
}
+
+ @SysUISingleton
+ static class LaunchEventsEmitter implements NotifActivityLaunchEvents {
+
+ private final ListenerSet<Listener> mListeners = new ListenerSet<>();
+
+ @Inject
+ LaunchEventsEmitter() {}
+
+ @Override
+ public void registerListener(@NonNull Listener listener) {
+ mListeners.addIfAbsent(listener);
+ }
+
+ @Override
+ public void unregisterListener(@NonNull Listener listener) {
+ mListeners.remove(listener);
+ }
+
+ private void notifyStartLaunchNotifActivity(NotificationEntry entry) {
+ for (Listener listener : mListeners) {
+ listener.onStartLaunchNotifActivity(entry);
+ }
+ }
+
+ private void notifyFinishLaunchNotifActivity(NotificationEntry entry) {
+ for (Listener listener : mListeners) {
+ listener.onFinishLaunchNotifActivity(entry);
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
index 59c9d0baea3f..a86ad6bc7012 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
@@ -27,7 +27,6 @@ import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.core.StatusBarInitializer;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.render.StatusBarNotifPanelEventSourceModule;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutListContainerModule;
@@ -60,8 +59,8 @@ import dagger.Subcomponent;
* outside the component. Should more items be moved *into* this component to avoid so many getters?
*/
@Subcomponent(modules = {
+ CentralSurfacesStartableModule.class,
NotificationStackScrollLayoutListContainerModule.class,
- StatusBarNotifPanelEventSourceModule.class,
StatusBarViewModule.class,
StatusBarNotificationActivityStarterModule.class,
StatusBarNotificationPresenterModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java
new file mode 100644
index 000000000000..21e5ad5778b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesStartableModule.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.dagger;
+
+import java.util.Set;
+
+import dagger.Module;
+import dagger.multibindings.Multibinds;
+
+@Module
+interface CentralSurfacesStartableModule {
+ @Multibinds
+ Set<CentralSurfacesComponent.Startable> multibindStartables();
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt
new file mode 100644
index 000000000000..c6c043aafb20
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ActivityLaunchAnimCoordinatorTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender
+import com.android.systemui.statusbar.phone.NotifActivityLaunchEvents
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import dagger.BindsInstance
+import dagger.Component
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+class ActivityLaunchAnimCoordinatorTest : SysuiTestCase() {
+
+ val activityLaunchEvents: NotifActivityLaunchEvents = mock()
+ val pipeline: NotifPipeline = mock()
+
+ val coordinator: ActivityLaunchAnimCoordinator =
+ DaggerTestActivityStarterCoordinatorComponent
+ .factory()
+ .create(activityLaunchEvents)
+ .coordinator
+
+ @Test
+ fun testNoLifetimeExtensionIfNoAssociatedActivityLaunch() {
+ coordinator.attach(pipeline)
+ val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
+ verify(pipeline).addNotificationLifetimeExtender(capture())
+ }
+ val fakeEntry = mock<NotificationEntry>().also {
+ whenever(it.key).thenReturn("0")
+ }
+ assertFalse(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
+ }
+
+ @Test
+ fun testNoLifetimeExtensionIfAssociatedActivityLaunchAlreadyEnded() {
+ coordinator.attach(pipeline)
+ val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
+ verify(pipeline).addNotificationLifetimeExtender(capture())
+ }
+ val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
+ verify(activityLaunchEvents).registerListener(capture())
+ }
+ val fakeEntry = mock<NotificationEntry>().also {
+ whenever(it.key).thenReturn("0")
+ }
+ eventListener.onStartLaunchNotifActivity(fakeEntry)
+ eventListener.onFinishLaunchNotifActivity(fakeEntry)
+ assertFalse(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
+ }
+
+ @Test
+ fun testLifetimeExtensionWhileActivityLaunchInProgress() {
+ coordinator.attach(pipeline)
+ val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
+ verify(pipeline).addNotificationLifetimeExtender(capture())
+ }
+ val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
+ verify(activityLaunchEvents).registerListener(capture())
+ }
+ val onEndLifetimeExtensionCallback =
+ mock<NotifLifetimeExtender.OnEndLifetimeExtensionCallback>()
+ lifetimeExtender.setCallback(onEndLifetimeExtensionCallback)
+
+ val fakeEntry = mock<NotificationEntry>().also {
+ whenever(it.key).thenReturn("0")
+ }
+ eventListener.onStartLaunchNotifActivity(fakeEntry)
+ assertTrue(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
+
+ eventListener.onFinishLaunchNotifActivity(fakeEntry)
+ verify(onEndLifetimeExtensionCallback).onEndLifetimeExtension(lifetimeExtender, fakeEntry)
+ }
+
+ @Test
+ fun testCancelLifetimeExtensionDoesNotInvokeCallback() {
+ coordinator.attach(pipeline)
+ val lifetimeExtender = withArgCaptor<NotifLifetimeExtender> {
+ verify(pipeline).addNotificationLifetimeExtender(capture())
+ }
+ val eventListener = withArgCaptor<NotifActivityLaunchEvents.Listener> {
+ verify(activityLaunchEvents).registerListener(capture())
+ }
+ val onEndLifetimeExtensionCallback =
+ mock<NotifLifetimeExtender.OnEndLifetimeExtensionCallback>()
+ lifetimeExtender.setCallback(onEndLifetimeExtensionCallback)
+
+ val fakeEntry = mock<NotificationEntry>().also {
+ whenever(it.key).thenReturn("0")
+ }
+ eventListener.onStartLaunchNotifActivity(fakeEntry)
+ assertTrue(lifetimeExtender.maybeExtendLifetime(fakeEntry, 0))
+
+ lifetimeExtender.cancelLifetimeExtension(fakeEntry)
+ eventListener.onFinishLaunchNotifActivity(fakeEntry)
+ verify(onEndLifetimeExtensionCallback, never())
+ .onEndLifetimeExtension(lifetimeExtender, fakeEntry)
+ }
+}
+
+@CoordinatorScope
+@Component(modules = [ActivityLaunchAnimCoordinatorModule::class])
+interface TestActivityStarterCoordinatorComponent {
+ val coordinator: ActivityLaunchAnimCoordinator
+
+ @Component.Factory
+ interface Factory {
+ fun create(
+ @BindsInstance activityLaunchEvents: NotifActivityLaunchEvents
+ ): TestActivityStarterCoordinatorComponent
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
index ee111715e5ea..6f8e5d8e514e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinatorTest.java
@@ -41,7 +41,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifStabilityManager;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.collection.render.NotifPanelEventSource;
+import com.android.systemui.statusbar.phone.NotifPanelEvents;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -67,12 +67,12 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
@Mock private StatusBarStateController mStatusBarStateController;
@Mock private Pluggable.PluggableListener<NotifStabilityManager> mInvalidateListener;
@Mock private HeadsUpManager mHeadsUpManager;
- @Mock private NotifPanelEventSource mNotifPanelEventSource;
+ @Mock private NotifPanelEvents mNotifPanelEvents;
@Mock private VisualStabilityProvider mVisualStabilityProvider;
@Captor private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessObserverCaptor;
@Captor private ArgumentCaptor<StatusBarStateController.StateListener> mSBStateListenerCaptor;
- @Captor private ArgumentCaptor<NotifPanelEventSource.Callbacks> mNotifPanelEventsCallbackCaptor;
+ @Captor private ArgumentCaptor<NotifPanelEvents.Listener> mNotifPanelEventsCallbackCaptor;
@Captor private ArgumentCaptor<NotifStabilityManager> mNotifStabilityManagerCaptor;
private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
@@ -80,7 +80,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
private WakefulnessLifecycle.Observer mWakefulnessObserver;
private StatusBarStateController.StateListener mStatusBarStateListener;
- private NotifPanelEventSource.Callbacks mNotifPanelEventsCallback;
+ private NotifPanelEvents.Listener mNotifPanelEventsCallback;
private NotifStabilityManager mNotifStabilityManager;
private NotificationEntry mEntry;
@@ -92,7 +92,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
mFakeExecutor,
mDumpManager,
mHeadsUpManager,
- mNotifPanelEventSource,
+ mNotifPanelEvents,
mStatusBarStateController,
mVisualStabilityProvider,
mWakefulnessLifecycle);
@@ -106,7 +106,7 @@ public class VisualStabilityCoordinatorTest extends SysuiTestCase {
verify(mStatusBarStateController).addCallback(mSBStateListenerCaptor.capture());
mStatusBarStateListener = mSBStateListenerCaptor.getValue();
- verify(mNotifPanelEventSource).registerCallbacks(mNotifPanelEventsCallbackCaptor.capture());
+ verify(mNotifPanelEvents).registerListener(mNotifPanelEventsCallbackCaptor.capture());
mNotifPanelEventsCallback = mNotifPanelEventsCallbackCaptor.getValue();
verify(mNotifPipeline).setVisualStabilityManager(mNotifStabilityManagerCaptor.capture());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 38412fd1fa9b..e58f557844b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -361,6 +361,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
private SysUiState mSysUiState;
@Mock
private NotificationListContainer mNotificationListContainer;
+ private NotificationPanelViewController.PanelEventsEmitter mPanelEventsEmitter;
private Optional<SysUIUnfoldComponent> mSysUIUnfoldComponent = Optional.empty();
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -488,6 +489,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
}).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
mMainHandler = new Handler(Looper.getMainLooper());
+ mPanelEventsEmitter = new NotificationPanelViewController.PanelEventsEmitter();
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
@@ -546,7 +548,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mQsFrameTranslateController,
mSysUiState,
mKeyguardUnlockAnimationController,
- mNotificationListContainer);
+ mNotificationListContainer,
+ mPanelEventsEmitter);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
() -> {},
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 ace7415f2c17..27179fd7be92 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
@@ -57,6 +57,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationClickNotifier;
@@ -130,7 +131,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private NotifPipeline mNotifPipeline;
@Mock
private NotificationVisibilityProvider mVisibilityProvider;
-
@Mock
private ActivityIntentHelper mActivityIntentHelper;
@Mock
@@ -145,14 +145,14 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
private ActivityLaunchAnimator mActivityLaunchAnimator;
@Mock
private InteractionJankMonitor mJankMonitor;
+ private StatusBarNotificationActivityStarter.LaunchEventsEmitter mLaunchEventsEmitter;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
-
private NotificationTestHelper mNotificationTestHelper;
private ExpandableNotificationRow mNotificationRow;
private ExpandableNotificationRow mBubbleNotificationRow;
private final Answer<Void> mCallOnDismiss = answerVoid(
- (ActivityStarter.OnDismissAction dismissAction, Runnable cancel,
+ (OnDismissAction dismissAction, Runnable cancel,
Boolean afterKeyguardGone) -> dismissAction.onDismiss());
private ArrayList<NotificationEntry> mActiveNotifications;
@@ -201,7 +201,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
NotificationListContainer.class),
headsUpManager,
mJankMonitor);
-
+ mLaunchEventsEmitter = new StatusBarNotificationActivityStarter.LaunchEventsEmitter();
mNotificationActivityStarter =
new StatusBarNotificationActivityStarter(
getContext(),
@@ -237,12 +237,13 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mock(NotificationPresenter.class),
mock(NotificationPanelViewController.class),
mActivityLaunchAnimator,
- notificationAnimationProvider
+ notificationAnimationProvider,
+ mLaunchEventsEmitter
);
// set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg
doAnswer(mCallOnDismiss).when(mActivityStarter).dismissKeyguardThenExecute(
- any(ActivityStarter.OnDismissAction.class), any(), anyBoolean());
+ any(OnDismissAction.class), any(), anyBoolean());
// set up addAfterKeyguardGoneRunnable to synchronously invoke the Runnable arg
doAnswer(answerVoid(Runnable::run))
@@ -402,4 +403,40 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// THEN display should try wake up for the full screen intent
verify(mCentralSurfaces).wakeUpForFullScreenIntent();
}
+
+ @Test
+ public void testNotifActivityStarterEventSourceStartEvent_onNotificationClicked() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onStartLaunchNotifActivity(mNotificationRow.getEntry());
+ }
+
+ @Test
+ public void testNotifActivityStarterEventSourceFinishEvent_dismissKeyguardCancelled() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ // set up dismissKeyguardThenExecute to synchronously invoke the cancel runnable arg
+ doAnswer(answerVoid(
+ (OnDismissAction dismissAction, Runnable cancel, Boolean afterKeyguardGone) ->
+ cancel.run()))
+ .when(mActivityStarter)
+ .dismissKeyguardThenExecute(any(OnDismissAction.class), any(), anyBoolean());
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+ }
+
+ @Test
+ public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse() {
+ NotifActivityLaunchEvents.Listener listener =
+ mock(NotifActivityLaunchEvents.Listener.class);
+ mLaunchEventsEmitter.registerListener(listener);
+ mNotificationActivityStarter
+ .onNotificationClicked(mNotificationRow.getEntry().getSbn(), mNotificationRow);
+ verify(listener).onFinishLaunchNotifActivity(mNotificationRow.getEntry());
+ }
}