Use SyncRtSurfaceTransactionApplier for recents enter/exit
To ensure proper synchronization, fixing jank.
Furthermore, we need to move the background choreographer to
vsync-sf pulse in order to allow for a smooth transition
background -> foreground when handling the touch.
Test: Swipe up, disable swipe, press recents to enter/exit
Bug: 80292740
Change-Id: Ie58616edf6432a0154d6dbf8497218721154d2b8
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 41bf729..308e92f 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 7b29323..8082d30 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -65,6 +65,7 @@
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
import com.android.systemui.shared.system.TransactionCompat;
import java.util.ArrayList;
@@ -348,11 +349,14 @@
clipHelper.updateTargetRect(targetRect);
clipHelper.prepareAnimation(false /* isOpening */);
+ SyncRtSurfaceTransactionApplier syncTransactionApplier =
+ new SyncRtSurfaceTransactionApplier(rootView);
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
valueAnimator.addUpdateListener((v) ->
- clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue()));
+ clipHelper.applyTransform(targetSet, (float) v.getAnimatedValue(),
+ syncTransactionApplier));
if (targetSet.isAnimatingHome()) {
// If we are animating home, fade in the opening targets
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 2b0c98f..ec2c318 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -46,6 +46,7 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
import java.util.List;
@@ -144,6 +145,8 @@
*/
public static ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
RemoteAnimationTargetCompat[] targets, final ClipAnimationHelper inOutHelper) {
+ SyncRtSurfaceTransactionApplier syncTransactionApplier =
+ new SyncRtSurfaceTransactionApplier(v);
final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
@@ -155,18 +158,10 @@
final RemoteAnimationTargetSet mTargetSet;
final RectF mThumbnailRect;
- private Surface mSurface;
- private long mFrameNumber;
{
mTargetSet = new RemoteAnimationTargetSet(targets, MODE_OPENING);
- inOutHelper.setTaskTransformCallback((t, app) -> {
- t.setAlpha(app.leash, mTaskAlpha.value);
-
- if (!skipViewChanges) {
- t.deferTransactionUntil(app.leash, mSurface, mFrameNumber);
- }
- });
+ inOutHelper.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
inOutHelper.prepareAnimation(true /* isOpening */);
inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
@@ -179,15 +174,8 @@
@Override
public void onUpdate(float percent) {
- mSurface = getSurface(v);
- mFrameNumber = mSurface != null ? getNextFrameNumber(mSurface) : -1;
- if (mFrameNumber == -1) {
- // Booo, not cool! Our surface got destroyed, so no reason to animate anything.
- Log.w(TAG, "Failed to animate, surface got destroyed.");
- return;
- }
-
- RectF taskBounds = inOutHelper.applyTransform(mTargetSet, 1 - percent);
+ RectF taskBounds = inOutHelper.applyTransform(mTargetSet, 1 - percent,
+ syncTransactionApplier);
if (!skipViewChanges) {
float scale = taskBounds.width() / mThumbnailRect.width();
v.setScaleX(scale);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index aecb66c..49a4ac8 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -49,6 +49,7 @@
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.ChoreographerCompat;
import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
/**
@@ -406,6 +407,6 @@
sRemoteUiThread.start();
}
new Handler(sRemoteUiThread.getLooper()).post(() ->
- mBackgroundThreadChoreographer = Choreographer.getInstance());
+ mBackgroundThreadChoreographer = ChoreographerCompat.getSfInstance());
}
}
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 84b2176..a1d0584 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -73,6 +73,7 @@
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
import com.android.systemui.shared.system.WindowCallbacksCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -180,6 +181,7 @@
private T mActivity;
private LayoutListener mLayoutListener;
private RecentsView mRecentsView;
+ private SyncRtSurfaceTransactionApplier mSyncTransactionApplier;
private QuickScrubController mQuickScrubController;
private AnimationFactory mAnimationFactory = (t) -> { };
@@ -346,6 +348,7 @@
}
mRecentsView = activity.getOverviewPanel();
+ mSyncTransactionApplier = new SyncRtSurfaceTransactionApplier(mRecentsView);
mQuickScrubController = mRecentsView.getQuickScrubController();
mLayoutListener = mActivityControlHelper.createLayoutListener(mActivity);
@@ -503,7 +506,11 @@
RecentsAnimationControllerCompat controller = mRecentsAnimationWrapper.getController();
if (controller != null) {
- mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, shift);
+
+ mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet, shift,
+ Looper.myLooper() == mMainThreadHandler.getLooper()
+ ? mSyncTransactionApplier
+ : null);
// TODO: This logic is spartanic!
boolean passedThreshold = shift > 0.12f;
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
index 8c7f104..62a169c 100644
--- a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -30,6 +30,7 @@
import android.os.Build;
import android.os.RemoteException;
import android.support.annotation.Nullable;
+import android.view.Surface;
import android.view.animation.Interpolator;
import com.android.launcher3.BaseDraggingActivity;
@@ -44,10 +45,13 @@
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplier.SurfaceParams;
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
/**
* Utility class to handle window clip animation
@@ -89,8 +93,8 @@
// Wether or not applyTransform has been called yet since prepareAnimation()
private boolean mIsFirstFrame = true;
- private BiConsumer<TransactionCompat, RemoteAnimationTargetCompat> mTaskTransformCallback =
- (t, a) -> { };
+ private BiFunction<RemoteAnimationTargetCompat, Float, Float> mTaskAlphaCallback =
+ (t, a1) -> a1;
private void updateSourceStack(RemoteAnimationTargetCompat target) {
mSourceInsets.set(target.contentInsets);
@@ -131,11 +135,11 @@
}
public void prepareAnimation(boolean isOpening) {
- mIsFirstFrame = true;
mBoostModeTargetLayers = isOpening ? MODE_OPENING : MODE_CLOSING;
}
- public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress) {
+ public RectF applyTransform(RemoteAnimationTargetSet targetSet, float progress,
+ @Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier) {
RectF currentRect;
mTmpRectF.set(mTargetRect);
Utilities.scaleRectFAboutCenter(mTmpRectF, mTargetScale);
@@ -155,35 +159,51 @@
mClipRect.bottom = (int)
(mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress));
- TransactionCompat transaction = new TransactionCompat();
- if (mIsFirstFrame) {
- RemoteAnimationProvider.prepareTargetsForFirstFrame(targetSet.unfilteredApps,
- transaction, mBoostModeTargetLayers);
- mIsFirstFrame = false;
- }
- for (RemoteAnimationTargetCompat app : targetSet.apps) {
- if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
- mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
- mTmpMatrix.postTranslate(app.position.x, app.position.y);
- transaction.setMatrix(app.leash, mTmpMatrix)
- .setWindowCrop(app.leash, mClipRect);
+ SurfaceParams[] params = new SurfaceParams[targetSet.unfilteredApps.length];
+ for (int i = 0; i < targetSet.unfilteredApps.length; i++) {
+ RemoteAnimationTargetCompat app = targetSet.unfilteredApps[i];
+ mTmpMatrix.setTranslate(app.position.x, app.position.y);
+ Rect crop = app.sourceContainerBounds;
+ float alpha = 1f;
+ if (app.mode == targetSet.targetMode) {
+ if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
+ mTmpMatrix.postTranslate(app.position.x, app.position.y);
+ crop = mClipRect;
+ }
+
+ if (app.isNotInRecents
+ || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
+ alpha = 1 - progress;
+ }
+
+ alpha = mTaskAlphaCallback.apply(app, alpha);
}
- if (app.isNotInRecents
- || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
- transaction.setAlpha(app.leash, 1 - progress);
- }
-
- mTaskTransformCallback.accept(transaction, app);
+ params[i] = new SurfaceParams(app.leash, alpha, mTmpMatrix, crop,
+ RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers));
}
- transaction.setEarlyWakeup();
- transaction.apply();
+ applyParams(syncTransactionApplier, params);
return currentRect;
}
- public void setTaskTransformCallback
- (BiConsumer<TransactionCompat, RemoteAnimationTargetCompat> callback) {
- mTaskTransformCallback = callback;
+ private void applyParams(@Nullable SyncRtSurfaceTransactionApplier syncTransactionApplier,
+ SurfaceParams[] params) {
+ if (syncTransactionApplier != null) {
+ syncTransactionApplier.scheduleApply(params);
+ } else {
+ TransactionCompat t = new TransactionCompat();
+ for (SurfaceParams param : params) {
+ SyncRtSurfaceTransactionApplier.applyParams(t, param);
+ }
+ t.setEarlyWakeup();
+ t.apply();
+ }
+ }
+
+ public void setTaskAlphaCallback(
+ BiFunction<RemoteAnimationTargetCompat, Float, Float> callback) {
+ mTaskAlphaCallback = callback;
}
public void offsetTarget(float scale, float offsetX, float offsetY, Interpolator interpolator) {
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
index 04b8be5..c372485 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationTargetSet.java
@@ -26,6 +26,7 @@
public final RemoteAnimationTargetCompat[] unfilteredApps;
public final RemoteAnimationTargetCompat[] apps;
+ public final int targetMode;
public RemoteAnimationTargetSet(RemoteAnimationTargetCompat[] apps, int targetMode) {
ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
@@ -39,6 +40,7 @@
this.unfilteredApps = apps;
this.apps = filteredApps.toArray(new RemoteAnimationTargetCompat[filteredApps.size()]);
+ this.targetMode = targetMode;
}
public RemoteAnimationTargetCompat findTask(int taskId) {