Merge "Extend lifetime of notifs during activity launch" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
89489bb5a8
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
annotation class CoordinatorScope
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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.KeyguardBypassController;
|
||||
import com.android.systemui.statusbar.phone.ShadeController;
|
||||
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.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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
@@ -3466,9 +3466,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3477,9 +3475,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4381,16 +4377,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) {
|
||||
@@ -5164,4 +5150,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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,
|
||||
() -> {},
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user