Override desktop tasks corner radius during recents transition

Set the corner radius of desktop task surfaces to 0 during recents
transitions so that corner radius doesn't interfere with the surface
bounds and corner radius applied to the RemoteAnimationTarget leashes.

Bug: 378657004
Test: manual
Flag: com.android.window.flags.enable_desktop_recents_transitions_corners_bugfix

Change-Id: Ia653ace883cabfcd573ac138cb22affd96f7f229
This commit is contained in:
Gustav Sennton
2024-12-18 09:39:52 +00:00
parent 239745aae9
commit 3bec45cdee
16 changed files with 81 additions and 22 deletions
@@ -98,6 +98,7 @@ import android.view.animation.Interpolator;
import android.widget.Toast;
import android.window.DesktopModeFlags;
import android.window.PictureInPictureSurfaceTransaction;
import android.window.TransitionInfo;
import android.window.WindowAnimationState;
import androidx.annotation.NonNull;
@@ -954,10 +955,10 @@ public abstract class AbsSwipeUpHandler<
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
super.onRecentsAnimationStart(controller, targets);
RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
super.onRecentsAnimationStart(controller, targets, transitionInfo);
if (targets.hasDesktopTasks(mContext)) {
mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets, transitionInfo);
} else {
int untrimmedAppCount = mRemoteTargetHandles.length;
mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(targets);
@@ -33,6 +33,7 @@ import android.content.Intent;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -491,7 +492,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
RecentsAnimationTargets targets, TransitionInfo info) {
mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED);
}
@@ -23,6 +23,7 @@ import android.os.SystemClock
import android.os.Trace
import android.util.Log
import android.view.View
import android.window.TransitionInfo
import androidx.annotation.BinderThread
import androidx.annotation.UiThread
import androidx.annotation.VisibleForTesting
@@ -369,6 +370,7 @@ constructor(
override fun onRecentsAnimationStart(
controller: RecentsAnimationController,
targets: RecentsAnimationTargets,
transitionInfo: TransitionInfo,
) {
Log.d(TAG, "recents animation started: $command")
updateRecentsViewFocus(command)
@@ -26,6 +26,7 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.util.ArraySet;
import android.view.RemoteAnimationTarget;
import android.window.TransitionInfo;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -93,7 +94,7 @@ public class RecentsAnimationCallbacks implements
RemoteAnimationTarget[] appTargets, Rect homeContentInsets,
Rect minimizedHomeBounds, Bundle extras) {
onAnimationStart(controller, appTargets, new RemoteAnimationTarget[0],
homeContentInsets, minimizedHomeBounds, extras);
homeContentInsets, minimizedHomeBounds, extras, /* transitionInfo= */ null);
}
// Called only in R+ platform
@@ -101,7 +102,8 @@ public class RecentsAnimationCallbacks implements
public final void onAnimationStart(RecentsAnimationControllerCompat animationController,
RemoteAnimationTarget[] appTargets,
RemoteAnimationTarget[] wallpaperTargets,
Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras) {
Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras,
TransitionInfo transitionInfo) {
long appCount = Arrays.stream(appTargets)
.filter(app -> app.mode == MODE_CLOSING)
.count();
@@ -141,7 +143,7 @@ public class RecentsAnimationCallbacks implements
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
ActiveGestureProtoLogProxy.logOnRecentsAnimationStart(targets.apps.length);
for (RecentsAnimationListener listener : getListeners()) {
listener.onRecentsAnimationStart(mController, targets);
listener.onRecentsAnimationStart(mController, targets, transitionInfo);
}
});
}
@@ -205,7 +207,7 @@ public class RecentsAnimationCallbacks implements
*/
public interface RecentsAnimationListener {
default void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {}
RecentsAnimationTargets targets, TransitionInfo transitionInfo) {}
/**
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
@@ -24,6 +24,7 @@ import android.content.Context;
import android.graphics.Rect;
import android.util.Log;
import android.view.RemoteAnimationTarget;
import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -213,7 +214,8 @@ public class RemoteTargetGluer {
* Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this creates distinct
* transform params per app in {@code targets.apps} list.
*/
public RemoteTargetHandle[] assignTargetsForDesktop(RemoteAnimationTargets targets) {
public RemoteTargetHandle[] assignTargetsForDesktop(
RemoteAnimationTargets targets, TransitionInfo transitionInfo) {
resizeRemoteTargetHandles(targets);
for (int i = 0; i < mRemoteTargetHandles.length; i++) {
@@ -222,6 +224,7 @@ public class RemoteTargetGluer {
.filter(target -> target.taskId != primaryTaskTarget.taskId).toList();
mRemoteTargetHandles[i].mTransformParams.setTargetSet(
createRemoteAnimationTargetsForTarget(targets, excludeTargets));
mRemoteTargetHandles[i].mTransformParams.setTransitionInfo(transitionInfo);
mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
}
return mRemoteTargetHandles;
@@ -45,6 +45,7 @@ import android.window.IOnBackInvokedCallback
import android.window.RemoteTransition
import android.window.TaskSnapshot
import android.window.TransitionFilter
import android.window.TransitionInfo
import androidx.annotation.MainThread
import androidx.annotation.VisibleForTesting
import androidx.annotation.WorkerThread
@@ -1174,6 +1175,7 @@ class SystemUiProxy @Inject constructor(@ApplicationContext private val context:
homeContentInsets: Rect?,
minimizedHomeBounds: Rect?,
extras: Bundle?,
transitionInfo: TransitionInfo?,
) =
listener.onAnimationStart(
RecentsAnimationControllerCompat(controller),
@@ -1186,6 +1188,7 @@ class SystemUiProxy @Inject constructor(@ApplicationContext private val context:
// https://developer.android.com/guide/components/aidl#Bundles
classLoader = SplitBounds::class.java.classLoader
},
transitionInfo,
)
override fun onAnimationCanceled(taskIds: IntArray?, taskSnapshots: Array<TaskSnapshot>?) =
@@ -36,6 +36,7 @@ import android.content.Intent;
import android.os.SystemProperties;
import android.util.Log;
import android.view.RemoteAnimationTarget;
import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -69,6 +70,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
private RecentsAnimationController mController;
private RecentsAnimationCallbacks mCallbacks;
private RecentsAnimationTargets mTargets;
private TransitionInfo mTransitionInfo;
private RecentsAnimationDeviceState mDeviceState;
// Temporary until we can hook into gesture state events
@@ -166,7 +168,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
ActiveGestureProtoLogProxy.logStartRecentsAnimationCallback(
"onRecentsAnimationStart");
@@ -180,6 +182,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
}
mController = controller;
mTargets = targets;
mTransitionInfo = transitionInfo;
// TODO(b/236226779): We can probably get away w/ setting mLastAppearedTaskTargets
// to all appeared targets directly vs just looking at running ones
int[] runningTaskIds = mLastGestureState.getRunningTaskIds(targets.apps.length > 1);
@@ -448,7 +451,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
public void notifyRecentsAnimationState(
RecentsAnimationCallbacks.RecentsAnimationListener listener) {
if (isRecentsAnimationRunning()) {
listener.onRecentsAnimationStart(mController, mTargets);
listener.onRecentsAnimationStart(mController, mTargets, mTransitionInfo);
}
// TODO: Do we actually need to report canceled/finished?
}
@@ -488,6 +491,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
mController = null;
mCallbacks = null;
mTargets = null;
mTransitionInfo = null;
mLastGestureState = null;
mLastAppearedTaskTargets = null;
}
@@ -189,7 +189,8 @@ public final class TaskViewUtils {
RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
recentsView.getSizeStrategy(), targets, forDesktop);
if (forDesktop) {
remoteTargetHandles = gluer.assignTargetsForDesktop(targets);
remoteTargetHandles =
gluer.assignTargetsForDesktop(targets, /* transitionInfo=*/ null);
} else if (v.containsMultipleTasks()) {
remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets,
((GroupedTaskView) v).getSplitBoundsConfig());
@@ -49,6 +49,7 @@ import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.animation.Interpolator;
import android.window.TransitionInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -126,8 +127,8 @@ public class RecentsWindowSwipeHandler extends AbsSwipeUpHandler<RecentsWindowMa
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
super.onRecentsAnimationStart(controller, targets);
RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
super.onRecentsAnimationStart(controller, targets, transitionInfo);
initTransformParams();
}
@@ -37,6 +37,7 @@ import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.RemoteAnimationTarget;
import android.view.VelocityTracker;
import android.window.TransitionInfo;
import com.android.app.animation.Interpolators;
import com.android.launcher3.R;
@@ -248,7 +249,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
mRecentsAnimationController = controller;
mTransformParams.setTargetSet(targets);
applyTransform();
@@ -28,6 +28,7 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
import android.view.MotionEvent;
import android.window.TransitionInfo;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorListeners;
@@ -172,7 +173,7 @@ public class ProgressDelegateInputConsumer implements InputConsumer,
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
mRecentsAnimationController = controller;
mStateCallback.setState(STATE_TARGET_RECEIVED);
}
@@ -678,7 +678,7 @@ public class SplitSelectStateController {
}
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
public void startAnimation(IBinder transition, TransitionInfo transitionInfo,
SurfaceControl.Transaction t,
IRemoteTransitionFinishedCallback finishedCallback) {
final Runnable finishAdapter = () -> {
@@ -708,7 +708,7 @@ public class SplitSelectStateController {
null /* nonApps */,
mStateManager,
mDepthController,
info, t, () -> {
transitionInfo, t, () -> {
finishAdapter.run();
cleanup(true /*success*/);
},
@@ -920,7 +920,7 @@ public class SplitSelectStateController {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
StatsLogManager.LauncherEvent launcherDesktopSplitEvent =
mSplitPosition == STAGE_POSITION_BOTTOM_OR_RIGHT ?
LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM :
@@ -30,6 +30,7 @@ import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.graphics.Rect;
import android.graphics.RectF;
import android.window.TransitionInfo;
import androidx.annotation.BinderThread;
@@ -122,7 +123,7 @@ public class SplitWithKeyboardShortcutController {
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
mController.setInitialTaskSelect(mRunningTaskInfo,
mLeftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT,
null /* itemInfo */,
@@ -19,9 +19,12 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import android.util.FloatProperty;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
import com.android.window.flags.Flags;
public class TransformParams {
@@ -56,6 +59,7 @@ public class TransformParams {
private float mTargetAlpha;
private float mCornerRadius;
private RemoteAnimationTargets mTargetSet;
private TransitionInfo mTransitionInfo;
private SurfaceTransactionApplier mSyncTransactionApplier;
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
@@ -106,6 +110,14 @@ public class TransformParams {
return this;
}
/**
* Provides the {@code TransitionInfo} of the transition that this transformation stems from.
*/
public TransformParams setTransitionInfo(TransitionInfo transitionInfo) {
mTransitionInfo = transitionInfo;
return this;
}
/**
* Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
* are computed based on these TransformParams.
@@ -152,6 +164,9 @@ public class TransformParams {
builder.setAlpha(getTargetAlpha());
}
targetProxy.onBuildTargetParams(builder, app, this);
// Override the corner radius for {@code app} with the leash used by Shell, so that it
// doesn't interfere with the window clip and corner radius applied here.
overrideChangeLeashCornerRadiusToZero(app, transaction.getTransaction());
}
// always put wallpaper layer to bottom.
@@ -163,6 +178,28 @@ public class TransformParams {
return transaction;
}
private void overrideChangeLeashCornerRadiusToZero(
RemoteAnimationTarget app, SurfaceControl.Transaction transaction) {
if (!Flags.enableDesktopRecentsTransitionsCornersBugfix()) {
return;
}
SurfaceControl changeLeash = getChangeLeashForApp(app);
if (changeLeash != null) {
transaction.setCornerRadius(changeLeash, 0);
}
}
private SurfaceControl getChangeLeashForApp(RemoteAnimationTarget app) {
if (mTransitionInfo == null) return null;
for (TransitionInfo.Change change : mTransitionInfo.getChanges()) {
if (change.getTaskInfo() == null) continue;
if (change.getTaskInfo().taskId == app.taskId) {
return change.getLeash();
}
}
return null;
}
// Pubic getters so outside packages can read the values.
public float getProgress() {
@@ -5867,7 +5867,8 @@ public abstract class RecentsView<
if (recentsAnimationTargets.hasDesktopTasks(mContext)) {
gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
true /* forDesktop */);
mRemoteTargetHandles = gluer.assignTargetsForDesktop(recentsAnimationTargets);
mRemoteTargetHandles = gluer.assignTargetsForDesktop(
recentsAnimationTargets, /* transitionInfo= */ null);
} else {
gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
false);
@@ -370,7 +370,7 @@ public abstract class AbsSwipeUpHandlerTestCase<
private void onRecentsAnimationStart(SWIPE_HANDLER absSwipeUpHandler) {
runOnMainSync(() -> absSwipeUpHandler.onRecentsAnimationStart(
mRecentsAnimationController, mRecentsAnimationTargets));
mRecentsAnimationController, mRecentsAnimationTargets, /* transitionInfo= */null));
}
protected static void runOnMainSync(Runnable runnable) {