summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Josh Yang <yzj@google.com> 2024-11-19 10:33:39 -0800
committer Josh Yang <yzj@google.com> 2024-11-27 11:35:40 -0800
commit5872195a63d3b3b1dbfd87b11458c37c624b74ee (patch)
tree65167ad835e93ebacabf1606b5dc916eeb01604b
parentcc6143da4aa4522bf08820cfa616ed443ca6e5ba (diff)
Add predictive back support in origin transition backend.
Flag: com.google.android.clockwork.systemui.flags.transitions_enable_origin_transitions_backend Bug: 381106230 Test: manual test using the test app Change-Id: I3abc797021de37d6a6596bcc1b79f7d40aa15eac
-rw-r--r--packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java106
-rw-r--r--packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java9
-rw-r--r--packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java86
3 files changed, 161 insertions, 40 deletions
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
index 0f5e3679cc5f..ca2b9578f2be 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/OriginRemoteTransition.java
@@ -16,6 +16,8 @@
package com.android.systemui.animation;
+import static android.view.WindowManager.TRANSIT_CHANGE;
+
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ValueAnimator;
@@ -39,6 +41,7 @@ import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.wm.shell.shared.TransitionUtil;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -90,7 +93,7 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
() -> {
mStartTransaction = t;
mFinishCallback = finishCallback;
- startAnimationInternal(info);
+ startAnimationInternal(info, /* states= */ null);
});
}
@@ -112,7 +115,13 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishCallback,
WindowAnimationState[] states) {
- logD("takeOverAnimation - " + info);
+ logD("takeOverAnimation - info=" + info + ", states=" + Arrays.toString(states));
+ mHandler.post(
+ () -> {
+ mStartTransaction = t;
+ mFinishCallback = finishCallback;
+ startAnimationInternal(info, states);
+ });
}
@Override
@@ -121,14 +130,19 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
mHandler.post(this::cancel);
}
- private void startAnimationInternal(TransitionInfo info) {
+ private void startAnimationInternal(
+ TransitionInfo info, @Nullable WindowAnimationState[] states) {
if (!prepareUIs(info)) {
logE("Unable to prepare UI!");
finishAnimation(/* finished= */ false);
return;
}
// Notify player that we are starting.
- mPlayer.onStart(info, mStartTransaction, mOrigin, mOriginTransaction);
+ mPlayer.onStart(info, states, mStartTransaction, mOrigin, mOriginTransaction);
+
+ // Apply the initial transactions in case the player forgot to apply them.
+ mOriginTransaction.commit();
+ mStartTransaction.apply();
// Start the animator.
mAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
@@ -205,7 +219,8 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
.setCornerRadius(leash, windowRadius)
.setWindowCrop(leash, bounds.width(), bounds.height());
}
- } else if (TransitionUtil.isClosingMode(mode)) {
+ } else if (TransitionUtil.isClosingMode(mode) || mode == TRANSIT_CHANGE) {
+ // TRANSIT_CHANGE refers to the closing window in predictive back animation.
closingSurfaces.add(change.getLeash());
// For closing surfaces, starting bounds are base bounds. Apply corner radius if
// it's full screen.
@@ -236,13 +251,8 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
// Attach origin UIComponent to origin leash.
mOriginTransaction = mOrigin.newTransaction();
- mOriginTransaction
- .attachToTransitionLeash(
- mOrigin, mOriginLeash, displayBounds.width(), displayBounds.height())
- .commit();
-
- // Apply all surface changes.
- mStartTransaction.apply();
+ mOriginTransaction.attachToTransitionLeash(
+ mOrigin, mOriginLeash, displayBounds.width(), displayBounds.height());
return true;
}
@@ -328,6 +338,58 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
/* baseBounds= */ maxBounds);
}
+ private static void applyWindowAnimationStates(
+ TransitionInfo info,
+ @Nullable WindowAnimationState[] states,
+ UIComponent closingApp,
+ UIComponent openingApp) {
+ if (states == null) {
+ // Nothing to apply.
+ return;
+ }
+ // Calculate bounds.
+ Rect maxClosingBounds = new Rect();
+ Rect maxOpeningBounds = new Rect();
+ for (int i = 0; i < info.getChanges().size(); i++) {
+ Rect bound = getBounds(states[i]);
+ if (bound == null) {
+ continue;
+ }
+ int mode = info.getChanges().get(i).getMode();
+ if (TransitionUtil.isOpeningMode(mode)) {
+ maxOpeningBounds.union(bound);
+ } else if (TransitionUtil.isClosingMode(mode) || mode == TRANSIT_CHANGE) {
+ // TRANSIT_CHANGE refers to the closing window in predictive back animation.
+ maxClosingBounds.union(bound);
+ }
+ }
+
+ // Intentionally use a new transaction instead of reusing the existing transaction since we
+ // want to apply window animation states first without committing any other pending changes
+ // in the existing transaction. The existing transaction is expected to be committed by the
+ // onStart() client callback together with client's custom transformation.
+ UIComponent.Transaction transaction = closingApp.newTransaction();
+ if (!maxClosingBounds.isEmpty()) {
+ logD("Applying closing window bounds: " + maxClosingBounds);
+ transaction.setBounds(closingApp, maxClosingBounds);
+ }
+ if (!maxOpeningBounds.isEmpty()) {
+ logD("Applying opening window bounds: " + maxOpeningBounds);
+ transaction.setBounds(openingApp, maxOpeningBounds);
+ }
+ transaction.commit();
+ }
+
+ @Nullable
+ private static Rect getBounds(@Nullable WindowAnimationState state) {
+ if (state == null || state.bounds == null) {
+ return null;
+ }
+ Rect out = new Rect();
+ state.bounds.roundOut(out);
+ return out;
+ }
+
/**
* An interface that represents an origin transitions.
*
@@ -338,9 +400,14 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
/**
* Called when an origin transition starts. This method exposes the raw {@link
* TransitionInfo} so that clients can extract more information from it.
+ *
+ * <p>Note: if this transition is taking over a predictive back animation, the {@link
+ * WindowAnimationState} will be passed to this method. The concrete implementation is
+ * expected to apply the {@link WindowAnimationState} before continuing the transition.
*/
default void onStart(
TransitionInfo transitionInfo,
+ @Nullable WindowAnimationState[] states,
SurfaceControl.Transaction sfTransaction,
UIComponent origin,
UIComponent.Transaction uiTransaction) {
@@ -351,12 +418,15 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
.registerTransactionForClass(
SurfaceUIComponent.class,
new SurfaceUIComponent.Transaction(sfTransaction));
- // Wrap surfaces and start.
- onStart(
- transactions,
- origin,
- wrapSurfaces(transitionInfo, /* isOpening= */ false),
- wrapSurfaces(transitionInfo, /* isOpening= */ true));
+ // Wrap surfaces.
+ UIComponent closingApp = wrapSurfaces(transitionInfo, /* isOpening= */ false);
+ UIComponent openingApp = wrapSurfaces(transitionInfo, /* isOpening= */ true);
+
+ // Restore the pending animation states coming from predictive back transition.
+ applyWindowAnimationStates(transitionInfo, states, closingApp, openingApp);
+
+ // Start.
+ onStart(transactions, origin, closingApp, openingApp);
}
/**
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
index 9cef43c3deba..cec740ad899b 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/ViewUIComponent.java
@@ -89,7 +89,6 @@ public class ViewUIComponent implements UIComponent {
mSurfaceControl =
new SurfaceControl.Builder().setName("ViewUIComponent").setBufferSize(w, h).build();
mSurface = new Surface(mSurfaceControl);
- forceDraw();
// Attach surface to transition leash
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -99,7 +98,13 @@ public class ViewUIComponent implements UIComponent {
mView.getViewTreeObserver().addOnDrawListener(mOnDrawListener);
// Make the view invisible AFTER the surface is shown.
- t.addTransactionCommittedListener(mView::post, () -> mView.setVisibility(View.INVISIBLE))
+ t.addTransactionCommittedListener(
+ mView::post,
+ () -> {
+ logD("Surface attached!");
+ forceDraw();
+ mView.setVisibility(View.INVISIBLE);
+ })
.apply();
}
diff --git a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
index 3cbb688ce7ca..6b26ac5f4692 100644
--- a/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
+++ b/packages/SystemUI/animation/lib/src/com/android/systemui/animation/server/IOriginTransitionsImpl.java
@@ -16,8 +16,10 @@
package com.android.systemui.animation.server;
+import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -26,6 +28,7 @@ import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.ComponentName;
import android.content.Context;
+import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -51,8 +54,8 @@ import java.util.function.Predicate;
/** An implementation of the {@link IOriginTransitions}. */
public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
- private static final boolean DEBUG = true;
private static final String TAG = "OriginTransitions";
+ private static final boolean DEBUG = Build.IS_USERDEBUG || Log.isLoggable(TAG, Log.DEBUG);
private final Object mLock = new Object();
private final ShellTransitions mShellTransitions;
@@ -149,18 +152,7 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
if (DEBUG) {
Log.d(TAG, "startAnimation: " + info);
}
- if (!mOnStarting.test(info)) {
- Log.w(TAG, "Skipping cancelled transition " + mTransition);
- t.addTransactionCommittedListener(
- mExecutor,
- () -> {
- try {
- finishCallback.onTransitionFinished(null, null);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to report finish.", e);
- }
- })
- .apply();
+ if (maybeInterceptTransition(info, t, finishCallback)) {
return;
}
mTransition.startAnimation(token, info, t, finishCallback);
@@ -191,6 +183,9 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
if (DEBUG) {
Log.d(TAG, "takeOverAnimation: " + info);
}
+ if (maybeInterceptTransition(info, t, finishCallback)) {
+ return;
+ }
mTransition.takeOverAnimation(transition, info, t, finishCallback, states);
}
@@ -207,6 +202,27 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
public String toString() {
return "RemoteTransitionDelegate{transition=" + mTransition + "}";
}
+
+ private boolean maybeInterceptTransition(
+ TransitionInfo info,
+ SurfaceControl.Transaction t,
+ IRemoteTransitionFinishedCallback finishCallback) {
+ if (!mOnStarting.test(info)) {
+ Log.w(TAG, "Intercepting cancelled transition " + mTransition);
+ t.addTransactionCommittedListener(
+ mExecutor,
+ () -> {
+ try {
+ finishCallback.onTransitionFinished(null, null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to report finish.", e);
+ }
+ })
+ .apply();
+ return true;
+ }
+ return false;
+ }
}
/** A data record containing the origin transition pieces. */
@@ -229,13 +245,25 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
if (mDestroyed) {
return false;
}
- TransitionFilter filter = createFilterForReverseTransition(info);
+ TransitionFilter filter =
+ createFilterForReverseTransition(
+ info, /* forPredictiveBackTakeover= */ false);
if (filter != null) {
if (DEBUG) {
Log.d(TAG, "Registering filter " + filter);
}
mShellTransitions.registerRemote(filter, mWrappedReturnTransition);
}
+ TransitionFilter takeoverFilter =
+ createFilterForReverseTransition(
+ info, /* forPredictiveBackTakeover= */ true);
+ if (takeoverFilter != null) {
+ if (DEBUG) {
+ Log.d(TAG, "Registering filter for takeover " + takeoverFilter);
+ }
+ mShellTransitions.registerRemoteForTakeover(
+ takeoverFilter, mWrappedReturnTransition);
+ }
return true;
}
}
@@ -331,7 +359,8 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
}
@Nullable
- private static TransitionFilter createFilterForReverseTransition(TransitionInfo info) {
+ private static TransitionFilter createFilterForReverseTransition(
+ TransitionInfo info, boolean forPredictiveBackTakeover) {
TaskInfo launchingTaskInfo = null;
TaskInfo launchedTaskInfo = null;
ComponentName launchingActivity = null;
@@ -365,7 +394,9 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
if (DEBUG) {
Log.d(
TAG,
- "createFilterForReverseTransition: launchingTaskInfo="
+ "createFilterForReverseTransition: forPredictiveBackTakeover="
+ + forPredictiveBackTakeover
+ + ", launchingTaskInfo="
+ launchingTaskInfo
+ ", launchedTaskInfo="
+ launchedTaskInfo
@@ -395,8 +426,20 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
+ " cookie!");
return null;
}
+ if (forPredictiveBackTakeover && launchedTaskInfo == null) {
+ // Predictive back take over currently only support cross-task transition.
+ Log.d(
+ TAG,
+ "createFilterForReverseTransition: skipped - unable to find launched task"
+ + " for predictive back takeover");
+ return null;
+ }
TransitionFilter filter = new TransitionFilter();
- filter.mTypeSet = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ if (forPredictiveBackTakeover) {
+ filter.mTypeSet = new int[] {TRANSIT_PREPARE_BACK_NAVIGATION};
+ } else {
+ filter.mTypeSet = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ }
// The opening activity of the return transition must match the activity we just closed.
TransitionFilter.Requirement req1 = new TransitionFilter.Requirement();
@@ -405,15 +448,18 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
launchingActivity == null ? launchingTaskInfo.topActivity : launchingActivity;
TransitionFilter.Requirement req2 = new TransitionFilter.Requirement();
- req2.mModes = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ if (forPredictiveBackTakeover) {
+ req2.mModes = new int[] {TRANSIT_CHANGE};
+ } else {
+ req2.mModes = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
+ }
if (launchedTaskInfo != null) {
// For task transitions, the closing task's cookie must match the task we just
// launched.
req2.mLaunchCookie = launchedTaskInfo.launchCookies.get(0);
} else {
// For activity transitions, the closing activity of the return transition must
- // match
- // the activity we just launched.
+ // match the activity we just launched.
req2.mTopActivity = launchedActivity;
}