Register the remote animation before starting an intent.
This CL calls IActivityTaskManager#registerRemoteAnimationForNextActivityStart before starting an intent for which the launch should be animated. This allows to also animate trampoline launches. This CL also adds a bit of logging to ActivityLaunchAnimator. Bug: 184726377 Test: Manual Change-Id: I4a3b95ed5e93e870d6ae0989d9c1ec771c9e85fc
This commit is contained in:
@@ -4,12 +4,14 @@ import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ValueAnimator
|
||||
import android.app.ActivityManager
|
||||
import android.app.ActivityTaskManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Rect
|
||||
import android.os.Looper
|
||||
import android.os.RemoteException
|
||||
import android.util.Log
|
||||
import android.util.MathUtils
|
||||
import android.view.IRemoteAnimationFinishedCallback
|
||||
import android.view.IRemoteAnimationRunner
|
||||
@@ -30,6 +32,8 @@ import kotlin.math.roundToInt
|
||||
* nicely into the starting window.
|
||||
*/
|
||||
class ActivityLaunchAnimator(context: Context) {
|
||||
private val TAG = this::class.java.simpleName
|
||||
|
||||
companion object {
|
||||
const val ANIMATION_DURATION = 500L
|
||||
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
|
||||
* 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].
|
||||
*/
|
||||
@JvmOverloads
|
||||
inline fun startIntentWithAnimation(
|
||||
fun startIntentWithAnimation(
|
||||
controller: Controller?,
|
||||
animate: Boolean = true,
|
||||
packageName: String? = null,
|
||||
intentStarter: (RemoteAnimationAdapter?) -> Int
|
||||
) {
|
||||
if (controller == null || !animate) {
|
||||
Log.d(TAG, "Starting intent with no animation")
|
||||
intentStarter(null)
|
||||
controller?.callOnIntentStartedOnMainThread(willAnimate = false)
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Starting intent with a launch animation")
|
||||
val runner = Runner(controller)
|
||||
val animationAdapter = RemoteAnimationAdapter(
|
||||
runner,
|
||||
ANIMATION_DURATION,
|
||||
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 willAnimate = launchResult == ActivityManager.START_TASK_TO_FRONT ||
|
||||
launchResult == ActivityManager.START_SUCCESS
|
||||
|
||||
Log.d(TAG, "launchResult=$launchResult willAnimate=$willAnimate")
|
||||
controller.callOnIntentStartedOnMainThread(willAnimate)
|
||||
|
||||
// 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) {
|
||||
if (Looper.myLooper() != Looper.getMainLooper()) {
|
||||
this.launchContainer.context.mainExecutor.execute {
|
||||
@@ -125,15 +148,21 @@ class ActivityLaunchAnimator(context: Context) {
|
||||
* Same as [startIntentWithAnimation] but allows [intentStarter] to throw a
|
||||
* [PendingIntent.CanceledException] which must then be handled by the caller. This is useful
|
||||
* 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)
|
||||
@JvmOverloads
|
||||
fun startPendingIntentWithAnimation(
|
||||
controller: Controller?,
|
||||
animate: Boolean = true,
|
||||
packageName: String? = null,
|
||||
intentStarter: PendingIntentStarter
|
||||
) {
|
||||
startIntentWithAnimation(controller, animate) { intentStarter.startPendingIntent(it) }
|
||||
startIntentWithAnimation(controller, animate, packageName) {
|
||||
intentStarter.startPendingIntent(it)
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a new animation [Runner] controlled by [controller]. */
|
||||
@@ -278,7 +307,7 @@ class ActivityLaunchAnimator(context: Context) {
|
||||
@VisibleForTesting
|
||||
inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
|
||||
private val launchContainer = controller.launchContainer
|
||||
@PublishedApi internal val context = launchContainer.context
|
||||
private val context = launchContainer.context
|
||||
private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer)
|
||||
private var animator: ValueAnimator? = null
|
||||
|
||||
@@ -294,7 +323,6 @@ class ActivityLaunchAnimator(context: Context) {
|
||||
// posting it.
|
||||
private var onTimeout = Runnable { onAnimationTimedOut() }
|
||||
|
||||
@PublishedApi
|
||||
internal fun postTimeout() {
|
||||
launchContainer.postDelayed(onTimeout, LAUNCH_TIMEOUT)
|
||||
}
|
||||
@@ -336,11 +364,13 @@ class ActivityLaunchAnimator(context: Context) {
|
||||
remoteAnimationNonAppTargets: Array<out RemoteAnimationTarget>,
|
||||
iCallback: IRemoteAnimationFinishedCallback
|
||||
) {
|
||||
Log.d(TAG, "Remote animation started")
|
||||
val window = remoteAnimationTargets.firstOrNull {
|
||||
it.mode == RemoteAnimationTarget.MODE_OPENING
|
||||
}
|
||||
|
||||
if (window == null) {
|
||||
Log.d(TAG, "Aborting the animation as no window is opening")
|
||||
removeTimeout()
|
||||
invokeCallback(iCallback)
|
||||
controller.onLaunchAnimationCancelled()
|
||||
@@ -399,10 +429,12 @@ class ActivityLaunchAnimator(context: Context) {
|
||||
|
||||
animator.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
|
||||
Log.d(TAG, "Animation started")
|
||||
controller.onLaunchAnimationStart(isExpandingFullyAbove)
|
||||
}
|
||||
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
Log.d(TAG, "Animation ended")
|
||||
invokeCallback(iCallback)
|
||||
controller.onLaunchAnimationEnd(isExpandingFullyAbove)
|
||||
}
|
||||
@@ -496,6 +528,7 @@ class ActivityLaunchAnimator(context: Context) {
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Remote animation timed out")
|
||||
timedOut = true
|
||||
controller.onLaunchAnimationCancelled()
|
||||
}
|
||||
@@ -505,6 +538,7 @@ class ActivityLaunchAnimator(context: Context) {
|
||||
return
|
||||
}
|
||||
|
||||
Log.d(TAG, "Remote animation was cancelled")
|
||||
cancelled = true
|
||||
removeTimeout()
|
||||
context.mainExecutor.execute {
|
||||
|
||||
@@ -2801,7 +2801,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
int[] result = new int[]{ActivityManager.START_CANCELED};
|
||||
|
||||
mActivityLaunchAnimator.startIntentWithAnimation(animController,
|
||||
areLaunchAnimationsEnabled(), (adapter) -> {
|
||||
areLaunchAnimationsEnabled(), intent.getPackage(), (adapter) -> {
|
||||
ActivityOptions options = new ActivityOptions(
|
||||
getActivityOptions(mDisplayId, adapter));
|
||||
options.setDisallowEnterPictureInPictureWhileLaunching(
|
||||
@@ -4563,7 +4563,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
animationController, this, intent.isActivity()) : null;
|
||||
|
||||
mActivityLaunchAnimator.startPendingIntentWithAnimation(
|
||||
controller, areLaunchAnimationsEnabled(),
|
||||
controller, areLaunchAnimationsEnabled(), intent.getCreatorPackage(),
|
||||
(animationAdapter) -> intent.sendAndReturnResult(null, 0, null, null, null,
|
||||
null, getActivityOptions(mDisplayId, animationAdapter)));
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
|
||||
@@ -437,7 +437,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
|
||||
mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
|
||||
!wasOccluded && mStatusBar.areLaunchAnimationsEnabled(),
|
||||
(adapter) -> {
|
||||
intent.getCreatorPackage(), (adapter) -> {
|
||||
long eventTime = row.getAndResetLastActionUpTime();
|
||||
Bundle options = eventTime > 0
|
||||
? getActivityOptions(
|
||||
@@ -469,6 +469,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
|
||||
mActivityLaunchAnimator.startIntentWithAnimation(
|
||||
animationController, mStatusBar.areLaunchAnimationsEnabled(),
|
||||
intent.getPackage(),
|
||||
(adapter) -> TaskStackBuilder.create(mContext)
|
||||
.addNextIntentWithParentStack(intent)
|
||||
.startActivities(getActivityOptions(
|
||||
@@ -499,7 +500,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
|
||||
true /* isActivityIntent */);
|
||||
|
||||
mActivityLaunchAnimator.startIntentWithAnimation(animationController,
|
||||
mStatusBar.areLaunchAnimationsEnabled(),
|
||||
mStatusBar.areLaunchAnimationsEnabled(), intent.getPackage(),
|
||||
(adapter) -> tsb.startActivities(
|
||||
getActivityOptions(mStatusBar.getDisplayId(), adapter),
|
||||
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
|
||||
// thread.
|
||||
thread {
|
||||
activityLaunchAnimator.startIntentWithAnimation(controller, animate, intentStarter)
|
||||
activityLaunchAnimator.startIntentWithAnimation(
|
||||
controller = controller,
|
||||
animate = animate,
|
||||
intentStarter = intentStarter
|
||||
)
|
||||
}.join()
|
||||
}
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
|
||||
verify(mShadeController, atLeastOnce()).collapsePanel();
|
||||
|
||||
verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(any(),
|
||||
eq(false) /* animate */, any());
|
||||
eq(false) /* animate */, any(), any());
|
||||
|
||||
verify(mAssistManager).hideAssist();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user