Merge "Register the remote animation before starting an intent." into sc-dev am: 8dab740d09
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14663313 Change-Id: If77af060e0d9b41d19ad0666698e02684dab020a
This commit is contained in:
committed by
Automerger Merge Worker
commit
fce6b1c050
@@ -4,12 +4,14 @@ import android.animation.Animator
|
|||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
|
import android.app.ActivityTaskManager
|
||||||
import android.app.PendingIntent
|
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.Looper
|
||||||
import android.os.RemoteException
|
import android.os.RemoteException
|
||||||
|
import android.util.Log
|
||||||
import android.util.MathUtils
|
import android.util.MathUtils
|
||||||
import android.view.IRemoteAnimationFinishedCallback
|
import android.view.IRemoteAnimationFinishedCallback
|
||||||
import android.view.IRemoteAnimationRunner
|
import android.view.IRemoteAnimationRunner
|
||||||
@@ -30,6 +32,8 @@ import kotlin.math.roundToInt
|
|||||||
* nicely into the starting window.
|
* nicely into the starting window.
|
||||||
*/
|
*/
|
||||||
class ActivityLaunchAnimator(context: Context) {
|
class ActivityLaunchAnimator(context: Context) {
|
||||||
|
private val TAG = this::class.java.simpleName
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ANIMATION_DURATION = 500L
|
const val ANIMATION_DURATION = 500L
|
||||||
const val ANIMATION_DURATION_FADE_OUT_CONTENT = 183L
|
const val ANIMATION_DURATION_FADE_OUT_CONTENT = 183L
|
||||||
@@ -78,29 +82,49 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
* If [controller] is null or [animate] is false, then the intent will be started and no
|
* If [controller] is null or [animate] is false, then the intent will be started and no
|
||||||
* animation will run.
|
* animation will run.
|
||||||
*
|
*
|
||||||
|
* If possible, you should pass the [packageName] of the intent that will be started so that
|
||||||
|
* trampoline activity launches will also be animated.
|
||||||
|
*
|
||||||
* This method will throw any exception thrown by [intentStarter].
|
* This method will throw any exception thrown by [intentStarter].
|
||||||
*/
|
*/
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
inline fun startIntentWithAnimation(
|
fun startIntentWithAnimation(
|
||||||
controller: Controller?,
|
controller: Controller?,
|
||||||
animate: Boolean = true,
|
animate: Boolean = true,
|
||||||
|
packageName: String? = null,
|
||||||
intentStarter: (RemoteAnimationAdapter?) -> Int
|
intentStarter: (RemoteAnimationAdapter?) -> Int
|
||||||
) {
|
) {
|
||||||
if (controller == null || !animate) {
|
if (controller == null || !animate) {
|
||||||
|
Log.d(TAG, "Starting intent with no animation")
|
||||||
intentStarter(null)
|
intentStarter(null)
|
||||||
controller?.callOnIntentStartedOnMainThread(willAnimate = false)
|
controller?.callOnIntentStartedOnMainThread(willAnimate = false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Starting intent with a launch animation")
|
||||||
val runner = Runner(controller)
|
val runner = Runner(controller)
|
||||||
val animationAdapter = RemoteAnimationAdapter(
|
val animationAdapter = RemoteAnimationAdapter(
|
||||||
runner,
|
runner,
|
||||||
ANIMATION_DURATION,
|
ANIMATION_DURATION,
|
||||||
ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
|
ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Register the remote animation for the given package to also animate trampoline
|
||||||
|
// activity launches.
|
||||||
|
if (packageName != null) {
|
||||||
|
try {
|
||||||
|
ActivityTaskManager.getService().registerRemoteAnimationForNextActivityStart(
|
||||||
|
packageName, animationAdapter)
|
||||||
|
} catch (e: RemoteException) {
|
||||||
|
Log.w(TAG, "Unable to register the remote animation", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
Log.d(TAG, "launchResult=$launchResult willAnimate=$willAnimate")
|
||||||
controller.callOnIntentStartedOnMainThread(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
|
||||||
@@ -110,7 +134,6 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PublishedApi
|
|
||||||
internal fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
|
internal fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
|
||||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||||
this.launchContainer.context.mainExecutor.execute {
|
this.launchContainer.context.mainExecutor.execute {
|
||||||
@@ -125,15 +148,21 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
* 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].
|
||||||
|
*
|
||||||
|
* If possible, you should pass the [packageName] of the intent that will be started so that
|
||||||
|
* trampoline activity launches will also be animated.
|
||||||
*/
|
*/
|
||||||
@Throws(PendingIntent.CanceledException::class)
|
@Throws(PendingIntent.CanceledException::class)
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun startPendingIntentWithAnimation(
|
fun startPendingIntentWithAnimation(
|
||||||
controller: Controller?,
|
controller: Controller?,
|
||||||
animate: Boolean = true,
|
animate: Boolean = true,
|
||||||
|
packageName: String? = null,
|
||||||
intentStarter: PendingIntentStarter
|
intentStarter: PendingIntentStarter
|
||||||
) {
|
) {
|
||||||
startIntentWithAnimation(controller, animate) { intentStarter.startPendingIntent(it) }
|
startIntentWithAnimation(controller, animate, packageName) {
|
||||||
|
intentStarter.startPendingIntent(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a new animation [Runner] controlled by [controller]. */
|
/** Create a new animation [Runner] controlled by [controller]. */
|
||||||
@@ -278,7 +307,7 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
|
inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
|
||||||
private val launchContainer = controller.launchContainer
|
private val launchContainer = controller.launchContainer
|
||||||
@PublishedApi internal val context = launchContainer.context
|
private val context = launchContainer.context
|
||||||
private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer)
|
private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer)
|
||||||
private var animator: ValueAnimator? = null
|
private var animator: ValueAnimator? = null
|
||||||
|
|
||||||
@@ -294,7 +323,6 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
// posting it.
|
// posting it.
|
||||||
private var onTimeout = Runnable { onAnimationTimedOut() }
|
private var onTimeout = Runnable { onAnimationTimedOut() }
|
||||||
|
|
||||||
@PublishedApi
|
|
||||||
internal fun postTimeout() {
|
internal fun postTimeout() {
|
||||||
launchContainer.postDelayed(onTimeout, LAUNCH_TIMEOUT)
|
launchContainer.postDelayed(onTimeout, LAUNCH_TIMEOUT)
|
||||||
}
|
}
|
||||||
@@ -336,11 +364,13 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
remoteAnimationNonAppTargets: Array<out RemoteAnimationTarget>,
|
remoteAnimationNonAppTargets: Array<out RemoteAnimationTarget>,
|
||||||
iCallback: IRemoteAnimationFinishedCallback
|
iCallback: IRemoteAnimationFinishedCallback
|
||||||
) {
|
) {
|
||||||
|
Log.d(TAG, "Remote animation started")
|
||||||
val window = remoteAnimationTargets.firstOrNull {
|
val window = remoteAnimationTargets.firstOrNull {
|
||||||
it.mode == RemoteAnimationTarget.MODE_OPENING
|
it.mode == RemoteAnimationTarget.MODE_OPENING
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window == null) {
|
if (window == null) {
|
||||||
|
Log.d(TAG, "Aborting the animation as no window is opening")
|
||||||
removeTimeout()
|
removeTimeout()
|
||||||
invokeCallback(iCallback)
|
invokeCallback(iCallback)
|
||||||
controller.onLaunchAnimationCancelled()
|
controller.onLaunchAnimationCancelled()
|
||||||
@@ -399,10 +429,12 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
|
|
||||||
animator.addListener(object : AnimatorListenerAdapter() {
|
animator.addListener(object : AnimatorListenerAdapter() {
|
||||||
override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
|
override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
|
||||||
|
Log.d(TAG, "Animation started")
|
||||||
controller.onLaunchAnimationStart(isExpandingFullyAbove)
|
controller.onLaunchAnimationStart(isExpandingFullyAbove)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationEnd(animation: Animator?) {
|
override fun onAnimationEnd(animation: Animator?) {
|
||||||
|
Log.d(TAG, "Animation ended")
|
||||||
invokeCallback(iCallback)
|
invokeCallback(iCallback)
|
||||||
controller.onLaunchAnimationEnd(isExpandingFullyAbove)
|
controller.onLaunchAnimationEnd(isExpandingFullyAbove)
|
||||||
}
|
}
|
||||||
@@ -496,6 +528,7 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Remote animation timed out")
|
||||||
timedOut = true
|
timedOut = true
|
||||||
controller.onLaunchAnimationCancelled()
|
controller.onLaunchAnimationCancelled()
|
||||||
}
|
}
|
||||||
@@ -505,6 +538,7 @@ class ActivityLaunchAnimator(context: Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "Remote animation was cancelled")
|
||||||
cancelled = true
|
cancelled = true
|
||||||
removeTimeout()
|
removeTimeout()
|
||||||
context.mainExecutor.execute {
|
context.mainExecutor.execute {
|
||||||
|
|||||||
@@ -2801,7 +2801,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
|||||||
int[] result = new int[]{ActivityManager.START_CANCELED};
|
int[] result = new int[]{ActivityManager.START_CANCELED};
|
||||||
|
|
||||||
mActivityLaunchAnimator.startIntentWithAnimation(animController,
|
mActivityLaunchAnimator.startIntentWithAnimation(animController,
|
||||||
areLaunchAnimationsEnabled(), (adapter) -> {
|
areLaunchAnimationsEnabled(), intent.getPackage(), (adapter) -> {
|
||||||
ActivityOptions options = new ActivityOptions(
|
ActivityOptions options = new ActivityOptions(
|
||||||
getActivityOptions(mDisplayId, adapter));
|
getActivityOptions(mDisplayId, adapter));
|
||||||
options.setDisallowEnterPictureInPictureWhileLaunching(
|
options.setDisallowEnterPictureInPictureWhileLaunching(
|
||||||
@@ -4565,7 +4565,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
|||||||
animationController, this, intent.isActivity()) : null;
|
animationController, this, intent.isActivity()) : null;
|
||||||
|
|
||||||
mActivityLaunchAnimator.startPendingIntentWithAnimation(
|
mActivityLaunchAnimator.startPendingIntentWithAnimation(
|
||||||
controller, areLaunchAnimationsEnabled(),
|
controller, areLaunchAnimationsEnabled(), intent.getCreatorPackage(),
|
||||||
(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) {
|
||||||
|
|||||||
@@ -437,7 +437,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
|||||||
|
|
||||||
mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
|
mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
|
||||||
!wasOccluded && mStatusBar.areLaunchAnimationsEnabled(),
|
!wasOccluded && mStatusBar.areLaunchAnimationsEnabled(),
|
||||||
(adapter) -> {
|
intent.getCreatorPackage(), (adapter) -> {
|
||||||
long eventTime = row.getAndResetLastActionUpTime();
|
long eventTime = row.getAndResetLastActionUpTime();
|
||||||
Bundle options = eventTime > 0
|
Bundle options = eventTime > 0
|
||||||
? getActivityOptions(
|
? getActivityOptions(
|
||||||
@@ -469,6 +469,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
|||||||
|
|
||||||
mActivityLaunchAnimator.startIntentWithAnimation(
|
mActivityLaunchAnimator.startIntentWithAnimation(
|
||||||
animationController, mStatusBar.areLaunchAnimationsEnabled(),
|
animationController, mStatusBar.areLaunchAnimationsEnabled(),
|
||||||
|
intent.getPackage(),
|
||||||
(adapter) -> TaskStackBuilder.create(mContext)
|
(adapter) -> TaskStackBuilder.create(mContext)
|
||||||
.addNextIntentWithParentStack(intent)
|
.addNextIntentWithParentStack(intent)
|
||||||
.startActivities(getActivityOptions(
|
.startActivities(getActivityOptions(
|
||||||
@@ -499,7 +500,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
|||||||
true /* isActivityIntent */);
|
true /* isActivityIntent */);
|
||||||
|
|
||||||
mActivityLaunchAnimator.startIntentWithAnimation(animationController,
|
mActivityLaunchAnimator.startIntentWithAnimation(animationController,
|
||||||
mStatusBar.areLaunchAnimationsEnabled(),
|
mStatusBar.areLaunchAnimationsEnabled(), intent.getPackage(),
|
||||||
(adapter) -> tsb.startActivities(
|
(adapter) -> tsb.startActivities(
|
||||||
getActivityOptions(mStatusBar.getDisplayId(), adapter),
|
getActivityOptions(mStatusBar.getDisplayId(), adapter),
|
||||||
UserHandle.CURRENT));
|
UserHandle.CURRENT));
|
||||||
|
|||||||
@@ -51,7 +51,11 @@ class ActivityLaunchAnimatorTest : SysuiTestCase() {
|
|||||||
// 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, animate, intentStarter)
|
activityLaunchAnimator.startIntentWithAnimation(
|
||||||
|
controller = controller,
|
||||||
|
animate = animate,
|
||||||
|
intentStarter = intentStarter
|
||||||
|
)
|
||||||
}.join()
|
}.join()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
|||||||
verify(mShadeController, atLeastOnce()).collapsePanel();
|
verify(mShadeController, atLeastOnce()).collapsePanel();
|
||||||
|
|
||||||
verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(any(),
|
verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(any(),
|
||||||
eq(false) /* animate */, any());
|
eq(false) /* animate */, any(), any());
|
||||||
|
|
||||||
verify(mAssistManager).hideAssist();
|
verify(mAssistManager).hideAssist();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user