Remove the ActivityLaunchAnimCoordinator.
This coordinator was recently added for the purpose of extending the lifetime of the notification entry while the launch animation played to prevent an entry instance mismatch crash when the app cancelled and reposted it on app launch. Unfortunately, this wasn't a scalable solution: 1) there was another launch scenario that wasn't covered by this animation, and 2) if the notification was auto-cancelled and reposted, this would not work because lifetime extenders are not allowed to extend the lifetime of user-dismissed notifications. That bug and these new crash cases were solved by alerting the NotifCollection when the animation starts, and then not dismissing the notification when it ends if it was already dismissed by the system server. That is implemented in Ia66ae5ade3fbfdd0436d54dcbeef720618622716, but makes this coordinator and the events it listened to unnecessary. Bug: 230540148 Bug: 227254780 Test: manually validate that crashes are still fixed Change-Id: I28f7226a30df7730dbae264bfd101397293a9a03
This commit is contained in:
@@ -1,95 +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.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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,6 @@ class NotifCoordinatorsImpl @Inject constructor(
|
||||
smartspaceDedupingCoordinator: SmartspaceDedupingCoordinator,
|
||||
viewConfigCoordinator: ViewConfigCoordinator,
|
||||
visualStabilityCoordinator: VisualStabilityCoordinator,
|
||||
activityLaunchAnimCoordinator: ActivityLaunchAnimCoordinator
|
||||
) : NotifCoordinators {
|
||||
|
||||
private val mCoordinators: MutableList<Coordinator> = ArrayList()
|
||||
@@ -93,7 +92,6 @@ class NotifCoordinatorsImpl @Inject constructor(
|
||||
mCoordinators.add(shadeEventCoordinator)
|
||||
mCoordinators.add(viewConfigCoordinator)
|
||||
mCoordinators.add(visualStabilityCoordinator)
|
||||
// mCoordinators.add(activityLaunchAnimCoordinator) // NOTE: will delete in followup CL
|
||||
if (notifPipelineFlags.isSmartspaceDedupingEnabled()) {
|
||||
mCoordinators.add(smartspaceDedupingCoordinator)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
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 dagger.Binds
|
||||
@@ -48,7 +47,6 @@ interface CoordinatorsSubcomponent {
|
||||
}
|
||||
|
||||
@Module(includes = [
|
||||
ActivityLaunchAnimCoordinatorModule::class,
|
||||
])
|
||||
private abstract class InternalCoordinatorsModule {
|
||||
@Binds
|
||||
|
||||
@@ -88,7 +88,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationSectionsMan
|
||||
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.policy.HeadsUpManager;
|
||||
@@ -111,7 +110,6 @@ import dagger.Provides;
|
||||
@Module(includes = {
|
||||
CoordinatorsModule.class,
|
||||
KeyguardNotificationVisibilityProviderModule.class,
|
||||
NotifActivityLaunchEventsModule.class,
|
||||
NotifPanelEventsModule.class,
|
||||
NotifPipelineChoreographerModule.class,
|
||||
NotificationSectionHeadersModule.class,
|
||||
|
||||
@@ -1,39 +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.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)
|
||||
}
|
||||
}
|
||||
@@ -1,30 +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.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);
|
||||
}
|
||||
@@ -41,7 +41,6 @@ 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;
|
||||
@@ -52,7 +51,6 @@ 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;
|
||||
@@ -77,7 +75,6 @@ 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;
|
||||
@@ -131,7 +128,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
private final ActivityLaunchAnimator mActivityLaunchAnimator;
|
||||
private final NotificationLaunchAnimatorControllerProvider mNotificationAnimationProvider;
|
||||
private final OnUserInteractionCallback mOnUserInteractionCallback;
|
||||
private final LaunchEventsEmitter mLaunchEventsEmitter;
|
||||
|
||||
private boolean mIsCollapsingToShowActivityOverLockscreen;
|
||||
|
||||
@@ -170,8 +166,7 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
NotificationPresenter presenter,
|
||||
NotificationPanelViewController panel,
|
||||
ActivityLaunchAnimator activityLaunchAnimator,
|
||||
NotificationLaunchAnimatorControllerProvider notificationAnimationProvider,
|
||||
LaunchEventsEmitter launchEventsEmitter) {
|
||||
NotificationLaunchAnimatorControllerProvider notificationAnimationProvider) {
|
||||
mContext = context;
|
||||
mCommandQueue = commandQueue;
|
||||
mMainThreadHandler = mainThreadHandler;
|
||||
@@ -207,7 +202,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
mNotificationPanel = panel;
|
||||
mActivityLaunchAnimator = activityLaunchAnimator;
|
||||
mNotificationAnimationProvider = notificationAnimationProvider;
|
||||
mLaunchEventsEmitter = launchEventsEmitter;
|
||||
|
||||
if (!mNotifPipelineFlags.isNewPipelineEnabled()) {
|
||||
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
|
||||
@@ -257,8 +251,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
return;
|
||||
}
|
||||
|
||||
mLaunchEventsEmitter.notifyStartLaunchNotifActivity(entry);
|
||||
|
||||
boolean isActivityIntent = intent != null && intent.isActivity() && !isBubble;
|
||||
final boolean willLaunchResolverActivity = isActivityIntent
|
||||
&& mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
|
||||
@@ -286,7 +278,7 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
} else {
|
||||
mActivityStarter.dismissKeyguardThenExecute(
|
||||
postKeyguardAction,
|
||||
() -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry),
|
||||
null,
|
||||
willLaunchResolverActivity);
|
||||
}
|
||||
}
|
||||
@@ -369,8 +361,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
mLogger.logExpandingBubble(entry);
|
||||
removeHunAfterClick(row);
|
||||
expandBubbleStackOnMainThread(entry);
|
||||
mMainThreadHandler.post(
|
||||
() -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
|
||||
} else {
|
||||
startNotificationIntent(intent, fillInIntent, entry, row, animate, isActivityIntent);
|
||||
}
|
||||
@@ -382,21 +372,11 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
|
||||
if (!canBubble && (shouldAutoCancel(entry.getSbn())
|
||||
|| mRemoteInputManager.isNotificationKeptForRemoteInputHistory(notificationKey))) {
|
||||
final Runnable locallyDismissNotification =
|
||||
final Runnable removeNotification =
|
||||
mOnUserInteractionCallback.registerFutureDismissal(entry, REASON_CLICK);
|
||||
// Immediately remove notification from visually showing.
|
||||
// We have to post the removal to the UI thread for synchronization.
|
||||
mMainThreadHandler.post(() -> {
|
||||
final Runnable removeNotification = () -> {
|
||||
locallyDismissNotification.run();
|
||||
if (!animate) {
|
||||
// If we're animating, this would be invoked after the activity launch
|
||||
// animation completes. Since we're not animating, the launch already
|
||||
// happened synchronously, so we notify the launch is complete here after
|
||||
// onDismiss.
|
||||
mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry);
|
||||
}
|
||||
};
|
||||
if (mPresenter.isCollapsing()) {
|
||||
// To avoid lags we're only performing the remove after the shade is collapsed
|
||||
mShadeController.addPostCollapseAction(removeNotification);
|
||||
@@ -404,10 +384,6 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
removeNotification.run();
|
||||
}
|
||||
});
|
||||
} else if (!canBubble && !animate) {
|
||||
// Not animating, this is the end of the launch flow (see above comment for more info).
|
||||
mMainThreadHandler.post(
|
||||
() -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry));
|
||||
}
|
||||
|
||||
// inform NMS that the notification was clicked
|
||||
@@ -479,13 +455,9 @@ class StatusBarNotificationActivityStarter implements NotificationActivityStarte
|
||||
boolean isActivityIntent) {
|
||||
mLogger.logStartNotificationIntent(entry);
|
||||
try {
|
||||
Runnable onFinishAnimationCallback = animate
|
||||
? () -> mLaunchEventsEmitter.notifyFinishLaunchNotifActivity(entry)
|
||||
: null;
|
||||
ActivityLaunchAnimator.Controller animationController =
|
||||
new StatusBarLaunchAnimatorController(
|
||||
mNotificationAnimationProvider
|
||||
.getAnimatorController(row, onFinishAnimationCallback),
|
||||
mNotificationAnimationProvider.getAnimatorController(row, null),
|
||||
mCentralSurfaces,
|
||||
isActivityIntent);
|
||||
mActivityLaunchAnimator.startPendingIntentWithAnimation(
|
||||
@@ -673,35 +645,4 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,138 +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.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
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,6 @@ import com.android.systemui.wmshell.BubblesManager;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
@@ -149,7 +148,6 @@ 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;
|
||||
@@ -206,7 +204,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
NotificationListContainer.class),
|
||||
headsUpManager,
|
||||
mJankMonitor);
|
||||
mLaunchEventsEmitter = new StatusBarNotificationActivityStarter.LaunchEventsEmitter();
|
||||
mNotificationActivityStarter =
|
||||
new StatusBarNotificationActivityStarter(
|
||||
getContext(),
|
||||
@@ -242,8 +239,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
mock(NotificationPresenter.class),
|
||||
mock(NotificationPanelViewController.class),
|
||||
mActivityLaunchAnimator,
|
||||
notificationAnimationProvider,
|
||||
mLaunchEventsEmitter
|
||||
notificationAnimationProvider
|
||||
);
|
||||
|
||||
// set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg
|
||||
@@ -421,60 +417,4 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
// THEN display should try wake up for the full screen intent
|
||||
verify(mCentralSurfaces).wakeUpForFullScreenIntent();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifActivityStarterEventSourceStartEvent_onNotificationClicked() {
|
||||
final NotificationEntry entry = mNotificationRow.getEntry();
|
||||
NotifActivityLaunchEvents.Listener listener =
|
||||
mock(NotifActivityLaunchEvents.Listener.class);
|
||||
mLaunchEventsEmitter.registerListener(listener);
|
||||
mNotificationActivityStarter.onNotificationClicked(entry, mNotificationRow);
|
||||
verify(listener).onStartLaunchNotifActivity(entry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifActivityStarterEventSourceFinishEvent_dismissKeyguardCancelled() {
|
||||
final NotificationEntry entry = mNotificationRow.getEntry();
|
||||
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(entry, mNotificationRow);
|
||||
verify(listener).onFinishLaunchNotifActivity(entry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse()
|
||||
throws Exception {
|
||||
final NotificationEntry entry = mNotificationRow.getEntry();
|
||||
NotifActivityLaunchEvents.Listener listener =
|
||||
mock(NotifActivityLaunchEvents.Listener.class);
|
||||
mLaunchEventsEmitter.registerListener(listener);
|
||||
mNotificationActivityStarter
|
||||
.onNotificationClicked(entry, mNotificationRow);
|
||||
ArgumentCaptor<ActivityLaunchAnimator.Controller> controllerCaptor =
|
||||
ArgumentCaptor.forClass(ActivityLaunchAnimator.Controller.class);
|
||||
verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(
|
||||
controllerCaptor.capture(), anyBoolean(), any(), any());
|
||||
controllerCaptor.getValue().onIntentStarted(false);
|
||||
verify(listener).onFinishLaunchNotifActivity(entry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotifActivityStarterEventSourceFinishEvent_postPanelCollapse_noAnimate() {
|
||||
final NotificationEntry entry = mNotificationRow.getEntry();
|
||||
NotifActivityLaunchEvents.Listener listener =
|
||||
mock(NotifActivityLaunchEvents.Listener.class);
|
||||
mLaunchEventsEmitter.registerListener(listener);
|
||||
when(mCentralSurfaces.shouldAnimateLaunch(anyBoolean())).thenReturn(false);
|
||||
mNotificationActivityStarter
|
||||
.onNotificationClicked(entry, mNotificationRow);
|
||||
verify(listener).onFinishLaunchNotifActivity(entry);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user