Merge "Fix HUN launch animation." into sc-dev

This commit is contained in:
Jordan Demeulenaere
2021-04-30 07:25:44 +00:00
committed by Android (Google) Code Review
8 changed files with 155 additions and 114 deletions

View File

@@ -8,6 +8,7 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.graphics.Matrix import android.graphics.Matrix
import android.graphics.Rect import android.graphics.Rect
import android.os.Looper
import android.os.RemoteException import android.os.RemoteException
import android.util.MathUtils import android.util.MathUtils
import android.view.IRemoteAnimationFinishedCallback import android.view.IRemoteAnimationFinishedCallback
@@ -73,16 +74,20 @@ class ActivityLaunchAnimator(context: Context) {
* in [Controller.onLaunchAnimationProgress]. No animation will start if there is no window * in [Controller.onLaunchAnimationProgress]. No animation will start if there is no window
* opening. * opening.
* *
* If [controller] is null, then the intent will be started and no animation will run. * If [controller] is null or [animate] is false, then the intent will be started and no
* animation will run.
* *
* This method will throw any exception thrown by [intentStarter]. * This method will throw any exception thrown by [intentStarter].
*/ */
@JvmOverloads
inline fun startIntentWithAnimation( inline fun startIntentWithAnimation(
controller: Controller?, controller: Controller?,
animate: Boolean = true,
intentStarter: (RemoteAnimationAdapter?) -> Int intentStarter: (RemoteAnimationAdapter?) -> Int
) { ) {
if (controller == null) { if (controller == null || !animate) {
intentStarter(null) intentStarter(null)
controller?.callOnIntentStartedOnMainThread(willAnimate = false)
return return
} }
@@ -95,7 +100,7 @@ class ActivityLaunchAnimator(context: Context) {
val launchResult = intentStarter(animationAdapter) val launchResult = intentStarter(animationAdapter)
val willAnimate = launchResult == ActivityManager.START_TASK_TO_FRONT || val willAnimate = launchResult == ActivityManager.START_TASK_TO_FRONT ||
launchResult == ActivityManager.START_SUCCESS launchResult == ActivityManager.START_SUCCESS
runner.context.mainExecutor.execute { controller.onIntentStarted(willAnimate) } controller.callOnIntentStartedOnMainThread(willAnimate)
// If we expect an animation, post a timeout to cancel it in case the remote animation is // If we expect an animation, post a timeout to cancel it in case the remote animation is
// never started. // never started.
@@ -104,17 +109,30 @@ class ActivityLaunchAnimator(context: Context) {
} }
} }
@PublishedApi
internal fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
if (Looper.myLooper() != Looper.getMainLooper()) {
this.getRootView().context.mainExecutor.execute {
this.onIntentStarted(willAnimate)
}
} else {
this.onIntentStarted(willAnimate)
}
}
/** /**
* Same as [startIntentWithAnimation] but allows [intentStarter] to throw a * Same as [startIntentWithAnimation] but allows [intentStarter] to throw a
* [PendingIntent.CanceledException] which must then be handled by the caller. This is useful * [PendingIntent.CanceledException] which must then be handled by the caller. This is useful
* for Java caller starting a [PendingIntent]. * for Java caller starting a [PendingIntent].
*/ */
@Throws(PendingIntent.CanceledException::class) @Throws(PendingIntent.CanceledException::class)
@JvmOverloads
fun startPendingIntentWithAnimation( fun startPendingIntentWithAnimation(
controller: Controller?, controller: Controller?,
animate: Boolean = true,
intentStarter: PendingIntentStarter intentStarter: PendingIntentStarter
) { ) {
startIntentWithAnimation(controller) { intentStarter.startPendingIntent(it) } startIntentWithAnimation(controller, animate) { intentStarter.startPendingIntent(it) }
} }
/** Create a new animation [Runner] controlled by [controller]. */ /** Create a new animation [Runner] controlled by [controller]. */

View File

@@ -6,6 +6,7 @@ import com.android.systemui.animation.ActivityLaunchAnimator
import com.android.systemui.statusbar.NotificationShadeDepthController import com.android.systemui.statusbar.NotificationShadeDepthController
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
@@ -14,7 +15,8 @@ import kotlin.math.max
class NotificationLaunchAnimatorControllerProvider( class NotificationLaunchAnimatorControllerProvider(
private val notificationShadeWindowViewController: NotificationShadeWindowViewController, private val notificationShadeWindowViewController: NotificationShadeWindowViewController,
private val notificationListContainer: NotificationListContainer, private val notificationListContainer: NotificationListContainer,
private val depthController: NotificationShadeDepthController private val depthController: NotificationShadeDepthController,
private val headsUpManager: HeadsUpManagerPhone
) { ) {
fun getAnimatorController( fun getAnimatorController(
notification: ExpandableNotificationRow notification: ExpandableNotificationRow
@@ -23,7 +25,8 @@ class NotificationLaunchAnimatorControllerProvider(
notificationShadeWindowViewController, notificationShadeWindowViewController,
notificationListContainer, notificationListContainer,
depthController, depthController,
notification notification,
headsUpManager
) )
} }
} }
@@ -37,8 +40,11 @@ class NotificationLaunchAnimatorController(
private val notificationShadeWindowViewController: NotificationShadeWindowViewController, private val notificationShadeWindowViewController: NotificationShadeWindowViewController,
private val notificationListContainer: NotificationListContainer, private val notificationListContainer: NotificationListContainer,
private val depthController: NotificationShadeDepthController, private val depthController: NotificationShadeDepthController,
private val notification: ExpandableNotificationRow private val notification: ExpandableNotificationRow,
private val headsUpManager: HeadsUpManagerPhone
) : ActivityLaunchAnimator.Controller { ) : ActivityLaunchAnimator.Controller {
private val notificationKey = notification.entry.sbn.key
override fun getRootView(): View = notification.rootView override fun getRootView(): View = notification.rootView
override fun createAnimatorState(): ActivityLaunchAnimator.State { override fun createAnimatorState(): ActivityLaunchAnimator.State {
@@ -76,12 +82,25 @@ class NotificationLaunchAnimatorController(
override fun onIntentStarted(willAnimate: Boolean) { override fun onIntentStarted(willAnimate: Boolean) {
notificationShadeWindowViewController.setExpandAnimationRunning(willAnimate) notificationShadeWindowViewController.setExpandAnimationRunning(willAnimate)
if (!willAnimate) {
removeHun(animate = true)
}
}
private fun removeHun(animate: Boolean) {
if (!headsUpManager.isAlerting(notificationKey)) {
return
}
headsUpManager.removeNotification(notificationKey, true /* releaseImmediately */, animate)
} }
override fun onLaunchAnimationCancelled() { override fun onLaunchAnimationCancelled() {
// TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started // TODO(b/184121838): Should we call InteractionJankMonitor.cancel if the animation started
// here? // here?
notificationShadeWindowViewController.setExpandAnimationRunning(false) notificationShadeWindowViewController.setExpandAnimationRunning(false)
removeHun(animate = true)
} }
override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
@@ -99,6 +118,7 @@ class NotificationLaunchAnimatorController(
notificationShadeWindowViewController.setExpandAnimationRunning(false) notificationShadeWindowViewController.setExpandAnimationRunning(false)
notificationListContainer.setExpandingNotification(null) notificationListContainer.setExpandingNotification(null)
applyParams(null) applyParams(null)
removeHun(animate = false)
} }
private fun applyParams(params: ExpandAnimationParameters?) { private fun applyParams(params: ExpandAnimationParameters?) {

View File

@@ -301,7 +301,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
} }
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
// HeadsUpManager public methods overrides: // HeadsUpManager public methods overrides and overloads:
@Override @Override
public boolean isTrackingHeadsUp() { public boolean isTrackingHeadsUp() {
@@ -318,6 +318,18 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
mSwipedOutKeys.add(key); mSwipedOutKeys.add(key);
} }
public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
boolean animate) {
if (animate) {
return removeNotification(key, releaseImmediately);
} else {
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
boolean removed = removeNotification(key, releaseImmediately);
mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
return removed;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////
// Dumpable overrides: // Dumpable overrides:

View File

@@ -1412,7 +1412,8 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider( mNotificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider(
mNotificationShadeWindowViewController, mNotificationShadeWindowViewController,
mStackScrollerController.getNotificationListContainer(), mStackScrollerController.getNotificationListContainer(),
mNotificationShadeDepthControllerLazy.get() mNotificationShadeDepthControllerLazy.get(),
mHeadsUpManager
); );
// TODO: inject this. // TODO: inject this.
@@ -2785,7 +2786,7 @@ public class StatusBar extends SystemUI implements DemoMode,
intent, mLockscreenUserManager.getCurrentUserId()); intent, mLockscreenUserManager.getCurrentUserId());
ActivityLaunchAnimator.Controller animController = null; ActivityLaunchAnimator.Controller animController = null;
if (animationController != null && areLaunchAnimationsEnabled()) { if (animationController != null) {
animController = dismissShade ? new StatusBarLaunchAnimatorController( animController = dismissShade ? new StatusBarLaunchAnimatorController(
animationController, this, true /* isLaunchForActivity */) animationController, this, true /* isLaunchForActivity */)
: animationController; : animationController;
@@ -2801,46 +2802,48 @@ public class StatusBar extends SystemUI implements DemoMode,
intent.setFlags( intent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(flags); intent.addFlags(flags);
int[] result = new int[] { ActivityManager.START_CANCELED }; int[] result = new int[]{ActivityManager.START_CANCELED};
mActivityLaunchAnimator.startIntentWithAnimation(animCallbackForLambda, (adapter) -> { mActivityLaunchAnimator.startIntentWithAnimation(animCallbackForLambda,
ActivityOptions options = new ActivityOptions( areLaunchAnimationsEnabled(), (adapter) -> {
getActivityOptions(mDisplayId, adapter)); ActivityOptions options = new ActivityOptions(
options.setDisallowEnterPictureInPictureWhileLaunching( getActivityOptions(mDisplayId, adapter));
disallowEnterPictureInPictureWhileLaunching); options.setDisallowEnterPictureInPictureWhileLaunching(
if (CameraIntents.isInsecureCameraIntent(intent)) { disallowEnterPictureInPictureWhileLaunching);
// Normally an activity will set it's requested rotation if (CameraIntents.isInsecureCameraIntent(intent)) {
// animation on its window. However when launching an activity // Normally an activity will set it's requested rotation
// causes the orientation to change this is too late. In these cases // animation on its window. However when launching an activity
// the default animation is used. This doesn't look good for // causes the orientation to change this is too late. In these cases
// the camera (as it rotates the camera contents out of sync // the default animation is used. This doesn't look good for
// with physical reality). So, we ask the WindowManager to // the camera (as it rotates the camera contents out of sync
// force the crossfade animation if an orientation change // with physical reality). So, we ask the WindowManager to
// happens to occur during the launch. // force the crossfade animation if an orientation change
options.setRotationAnimationHint( // happens to occur during the launch.
WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS); options.setRotationAnimationHint(
} WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS);
if (intent.getAction() == Settings.Panel.ACTION_VOLUME) { }
// Settings Panel is implemented as activity(not a dialog), so if (intent.getAction() == Settings.Panel.ACTION_VOLUME) {
// underlying app is paused and may enter picture-in-picture mode // Settings Panel is implemented as activity(not a dialog), so
// as a result. // underlying app is paused and may enter picture-in-picture mode
// So we need to disable picture-in-picture mode here // as a result.
// if it is volume panel. // So we need to disable picture-in-picture mode here
options.setDisallowEnterPictureInPictureWhileLaunching(true); // if it is volume panel.
} options.setDisallowEnterPictureInPictureWhileLaunching(true);
}
try { try {
result[0] = ActivityTaskManager.getService().startActivityAsUser( result[0] = ActivityTaskManager.getService().startActivityAsUser(
null, mContext.getBasePackageName(), mContext.getAttributionTag(), null, mContext.getBasePackageName(),
intent, mContext.getAttributionTag(),
intent.resolveTypeIfNeeded(mContext.getContentResolver()), intent,
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, intent.resolveTypeIfNeeded(mContext.getContentResolver()),
options.toBundle(), UserHandle.CURRENT.getIdentifier()); null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
} catch (RemoteException e) { options.toBundle(), UserHandle.CURRENT.getIdentifier());
Log.w(TAG, "Unable to start activity", e); } catch (RemoteException e) {
} Log.w(TAG, "Unable to start activity", e);
return result[0]; }
}); return result[0];
});
if (callback != null) { if (callback != null) {
callback.onActivityStarted(result[0]); callback.onActivityStarted(result[0]);
@@ -4559,19 +4562,17 @@ public class StatusBar extends SystemUI implements DemoMode,
&& mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(), && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
mLockscreenUserManager.getCurrentUserId()); mLockscreenUserManager.getCurrentUserId());
boolean animate = animationController != null && areLaunchAnimationsEnabled(); boolean collapse = animationController == null;
boolean collapse = !animate;
executeActionDismissingKeyguard(() -> { executeActionDismissingKeyguard(() -> {
try { try {
// We wrap animationCallback with a StatusBarLaunchAnimatorController so that the // We wrap animationCallback with a StatusBarLaunchAnimatorController so that the
// shade is collapsed after the animation (or when it is cancelled, aborted, etc). // shade is collapsed after the animation (or when it is cancelled, aborted, etc).
ActivityLaunchAnimator.Controller controller = ActivityLaunchAnimator.Controller controller =
animate ? new StatusBarLaunchAnimatorController(animationController, this, animationController != null ? new StatusBarLaunchAnimatorController(
intent.isActivity()) animationController, this, intent.isActivity()) : null;
: null;
mActivityLaunchAnimator.startPendingIntentWithAnimation( mActivityLaunchAnimator.startPendingIntentWithAnimation(
controller, controller, areLaunchAnimationsEnabled(),
(animationAdapter) -> intent.sendAndReturnResult(null, 0, null, null, null, (animationAdapter) -> intent.sendAndReturnResult(null, 0, null, null, null,
null, getActivityOptions(mDisplayId, animationAdapter))); null, getActivityOptions(mDisplayId, animationAdapter)));
} catch (PendingIntent.CanceledException e) { } catch (PendingIntent.CanceledException e) {

View File

@@ -283,7 +283,13 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey()); mLogger.logHandleClickAfterKeyguardDismissed(entry.getKey());
// TODO: Some of this code may be able to move to NotificationEntryManager. // TODO: Some of this code may be able to move to NotificationEntryManager.
removeHUN(row); String key = row.getEntry().getSbn().getKey();
if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
// Release the HUN notification to the shade.
if (mPresenter.isPresenterFullyCollapsed()) {
HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
}
}
final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed( final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
entry, row, controller, intent, entry, row, controller, intent,
@@ -331,6 +337,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
// bypass work challenge // bypass work challenge
if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId, if (mStatusBarRemoteInputCallback.startWorkChallengeIfNecessary(userId,
intent.getIntentSender(), notificationKey)) { intent.getIntentSender(), notificationKey)) {
removeHUN(row);
// Show work challenge, do not run PendingIntent and // Show work challenge, do not run PendingIntent and
// remove notification // remove notification
collapseOnMainThread(); collapseOnMainThread();
@@ -350,6 +357,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
final boolean canBubble = entry.canBubble(); final boolean canBubble = entry.canBubble();
if (canBubble) { if (canBubble) {
mLogger.logExpandingBubble(notificationKey); mLogger.logExpandingBubble(notificationKey);
removeHUN(row);
expandBubbleStackOnMainThread(entry); expandBubbleStackOnMainThread(entry);
} else { } else {
startNotificationIntent( startNotificationIntent(
@@ -422,14 +430,13 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
boolean isActivityIntent) { boolean isActivityIntent) {
mLogger.logStartNotificationIntent(entry.getKey(), intent); mLogger.logStartNotificationIntent(entry.getKey(), intent);
try { try {
ActivityLaunchAnimator.Controller animationController = null; ActivityLaunchAnimator.Controller animationController =
if (!wasOccluded && mStatusBar.areLaunchAnimationsEnabled()) { new StatusBarLaunchAnimatorController(
animationController = new StatusBarLaunchAnimatorController( mNotificationAnimationProvider.getAnimatorController(row), mStatusBar,
mNotificationAnimationProvider.getAnimatorController(row), mStatusBar, isActivityIntent);
isActivityIntent);
}
mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController, mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
!wasOccluded && mStatusBar.areLaunchAnimationsEnabled(),
(adapter) -> { (adapter) -> {
long eventTime = row.getAndResetLastActionUpTime(); long eventTime = row.getAndResetLastActionUpTime();
Bundle options = eventTime > 0 Bundle options = eventTime > 0
@@ -442,13 +449,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
return intent.sendAndReturnResult(mContext, 0, fillInIntent, null, return intent.sendAndReturnResult(mContext, 0, fillInIntent, null,
null, null, options); null, null, options);
}); });
// Note that other cases when we should still collapse (like activity already on top) is
// handled by the StatusBarLaunchAnimatorController.
boolean shouldCollapse = animationController == null;
if (shouldCollapse) {
collapseOnMainThread();
}
} catch (PendingIntent.CanceledException e) { } catch (PendingIntent.CanceledException e) {
// the stack trace isn't very helpful here. // the stack trace isn't very helpful here.
// Just log the exception message. // Just log the exception message.
@@ -462,34 +462,19 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
ExpandableNotificationRow row) { ExpandableNotificationRow row) {
mActivityStarter.dismissKeyguardThenExecute(() -> { mActivityStarter.dismissKeyguardThenExecute(() -> {
AsyncTask.execute(() -> { AsyncTask.execute(() -> {
ActivityLaunchAnimator.Controller animationController = null; ActivityLaunchAnimator.Controller animationController =
if (mStatusBar.areLaunchAnimationsEnabled()) { new StatusBarLaunchAnimatorController(
animationController = new StatusBarLaunchAnimatorController( mNotificationAnimationProvider.getAnimatorController(row),
mNotificationAnimationProvider.getAnimatorController(row), mStatusBar, mStatusBar, true /* isActivityIntent */);
true /* isActivityIntent */);
}
mActivityLaunchAnimator.startIntentWithAnimation( mActivityLaunchAnimator.startIntentWithAnimation(
animationController, animationController, mStatusBar.areLaunchAnimationsEnabled(),
(adapter) -> TaskStackBuilder.create(mContext) (adapter) -> TaskStackBuilder.create(mContext)
.addNextIntentWithParentStack(intent) .addNextIntentWithParentStack(intent)
.startActivities(getActivityOptions( .startActivities(getActivityOptions(
mStatusBar.getDisplayId(), mStatusBar.getDisplayId(),
adapter), adapter),
new UserHandle(UserHandle.getUserId(appUid)))); new UserHandle(UserHandle.getUserId(appUid))));
// Note that other cases when we should still collapse (like activity already on
// top) is handled by the StatusBarLaunchAnimatorController.
boolean shouldCollapse = animationController == null;
// Putting it back on the main thread, since we're touching views
mMainThreadHandler.post(() -> {
removeHUN(row);
if (shouldCollapse) {
mCommandQueue.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
true /* force */);
}
});
}); });
return true; return true;
}, null, false /* afterKeyguardGone */); }, null, false /* afterKeyguardGone */);
@@ -508,26 +493,16 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
tsb.addNextIntent(intent); tsb.addNextIntent(intent);
} }
ActivityLaunchAnimator.Controller animationController = null; ActivityLaunchAnimator.Controller animationController =
if (mStatusBar.areLaunchAnimationsEnabled()) { new StatusBarLaunchAnimatorController(
animationController = new StatusBarLaunchAnimatorController( ActivityLaunchAnimator.Controller.fromView(view), mStatusBar,
ActivityLaunchAnimator.Controller.fromView(view), mStatusBar, true /* isActivityIntent */);
true /* isActivityIntent */);
}
mActivityLaunchAnimator.startIntentWithAnimation(animationController, mActivityLaunchAnimator.startIntentWithAnimation(animationController,
mStatusBar.areLaunchAnimationsEnabled(),
(adapter) -> tsb.startActivities( (adapter) -> tsb.startActivities(
getActivityOptions(mStatusBar.getDisplayId(), adapter), getActivityOptions(mStatusBar.getDisplayId(), adapter),
UserHandle.CURRENT)); UserHandle.CURRENT));
// Note that other cases when we should still collapse (like activity already on
// top) is handled by the StatusBarLaunchAnimatorController.
boolean shouldCollapse = animationController == null;
if (shouldCollapse) {
// Putting it back on the main thread, since we're touching views
mMainThreadHandler.post(() -> mCommandQueue.animateCollapsePanels(
CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */));
}
}); });
return true; return true;
}, null, false /* afterKeyguardGone */); }, null, false /* afterKeyguardGone */);
@@ -536,11 +511,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private void removeHUN(ExpandableNotificationRow row) { private void removeHUN(ExpandableNotificationRow row) {
String key = row.getEntry().getSbn().getKey(); String key = row.getEntry().getSbn().getKey();
if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) { if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(key)) {
// Release the HUN notification to the shade.
if (mPresenter.isPresenterFullyCollapsed()) {
HeadsUpUtil.setIsClickedHeadsUpNotification(row, true);
}
// In most cases, when FLAG_AUTO_CANCEL is set, the notification will // In most cases, when FLAG_AUTO_CANCEL is set, the notification will
// become canceled shortly by NoMan, but we can't assume that. // become canceled shortly by NoMan, but we can't assume that.
mHeadsUpManager.removeNotification(key, true /* releaseImmediately */); mHeadsUpManager.removeNotification(key, true /* releaseImmediately */);

View File

@@ -341,7 +341,6 @@ interface SmartActionInflater {
activityStarter.startPendingIntentDismissingKeyguard(action.actionIntent, entry.row) { activityStarter.startPendingIntentDismissingKeyguard(action.actionIntent, entry.row) {
smartReplyController smartReplyController
.smartActionClicked(entry, actionIndex, action, smartActions.fromAssistant) .smartActionClicked(entry, actionIndex, action, smartActions.fromAssistant)
headsUpManager.removeNotification(entry.key, true /* releaseImmediately */)
} }
} }
} }

View File

@@ -44,12 +44,13 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
private fun startIntentWithAnimation( private fun startIntentWithAnimation(
controller: ActivityLaunchAnimator.Controller? = this.controller, controller: ActivityLaunchAnimator.Controller? = this.controller,
animate: Boolean = true,
intentStarter: (RemoteAnimationAdapter?) -> Int intentStarter: (RemoteAnimationAdapter?) -> Int
) { ) {
// We start in a new thread so that we can ensure that the callbacks are called in the main // We start in a new thread so that we can ensure that the callbacks are called in the main
// thread. // thread.
thread { thread {
activityLaunchAnimator.startIntentWithAnimation(controller, intentStarter) activityLaunchAnimator.startIntentWithAnimation(controller, animate, intentStarter)
}.join() }.join()
} }
@@ -94,6 +95,16 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
assertFalse(willAnimateCaptor.value) assertFalse(willAnimateCaptor.value)
} }
@Test
fun doesNotAnimateIfAnimateIsFalse() {
val willAnimateCaptor = ArgumentCaptor.forClass(Boolean::class.java)
startIntentWithAnimation(animate = false) { ActivityManager.START_SUCCESS }
waitForIdleSync()
verify(controller).onIntentStarted(willAnimateCaptor.capture())
assertFalse(willAnimateCaptor.value)
}
@Test @Test
fun doesNotStartIfAnimationIsCancelled() { fun doesNotStartIfAnimationIsCancelled() {
val runner = activityLaunchAnimator.createRunner(controller) val runner = activityLaunchAnimator.createRunner(controller)

View File

@@ -61,6 +61,7 @@ import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -73,6 +74,7 @@ import com.android.systemui.statusbar.notification.interruption.NotificationInte
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback; import com.android.systemui.statusbar.notification.row.OnUserInteractionCallback;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.util.time.FakeSystemClock;
@@ -184,6 +186,14 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
when(mOnUserInteractionCallback.getGroupSummaryToDismiss(mNotificationRow.getEntry())) when(mOnUserInteractionCallback.getGroupSummaryToDismiss(mNotificationRow.getEntry()))
.thenReturn(null); .thenReturn(null);
HeadsUpManagerPhone headsUpManager = mock(HeadsUpManagerPhone.class);
NotificationLaunchAnimatorControllerProvider notificationAnimationProvider =
new NotificationLaunchAnimatorControllerProvider(
mock(NotificationShadeWindowViewController.class), mock(
NotificationListContainer.class),
mock(NotificationShadeDepthController.class),
headsUpManager);
mNotificationActivityStarter = mNotificationActivityStarter =
new StatusBarNotificationActivityStarter.Builder( new StatusBarNotificationActivityStarter.Builder(
getContext(), getContext(),
@@ -192,7 +202,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mUiBgExecutor, mUiBgExecutor,
mEntryManager, mEntryManager,
mNotifPipeline, mNotifPipeline,
mock(HeadsUpManagerPhone.class), headsUpManager,
mActivityStarter, mActivityStarter,
mClickNotifier, mClickNotifier,
mock(StatusBarStateController.class), mock(StatusBarStateController.class),
@@ -220,8 +230,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
.setNotificationPanelViewController( .setNotificationPanelViewController(
mock(NotificationPanelViewController.class)) mock(NotificationPanelViewController.class))
.setActivityLaunchAnimator(mActivityLaunchAnimator) .setActivityLaunchAnimator(mActivityLaunchAnimator)
.setNotificationAnimatorControllerProvider( .setNotificationAnimatorControllerProvider(notificationAnimationProvider)
mock(NotificationLaunchAnimatorControllerProvider.class))
.build(); .build();
// set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg // set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg
@@ -259,7 +268,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
// Then // Then
verify(mShadeController, atLeastOnce()).collapsePanel(); verify(mShadeController, atLeastOnce()).collapsePanel();
verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(eq(null), any()); verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(any(),
eq(false) /* animate */, any());
verify(mAssistManager).hideAssist(); verify(mAssistManager).hideAssist();