1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.quickstep.util;
17 
18 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
19 
20 import static com.android.launcher3.Flags.enableGridOnlyOverview;
21 import static com.android.launcher3.states.RotationHelper.deltaRotation;
22 import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
23 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
24 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
25 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
26 import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
27 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
28 import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
29 import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
30 import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
31 
32 import android.animation.TimeInterpolator;
33 import android.content.Context;
34 import android.content.res.Resources;
35 import android.graphics.Matrix;
36 import android.graphics.PointF;
37 import android.graphics.Rect;
38 import android.graphics.RectF;
39 import android.util.Log;
40 import android.view.RemoteAnimationTarget;
41 import android.view.animation.Interpolator;
42 
43 import androidx.annotation.NonNull;
44 import androidx.annotation.Nullable;
45 
46 import com.android.app.animation.Interpolators;
47 import com.android.launcher3.DeviceProfile;
48 import com.android.launcher3.Utilities;
49 import com.android.launcher3.anim.AnimatedFloat;
50 import com.android.launcher3.anim.PendingAnimation;
51 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
52 import com.android.launcher3.util.TraceHelper;
53 import com.android.quickstep.BaseActivityInterface;
54 import com.android.quickstep.BaseContainerInterface;
55 import com.android.quickstep.TaskAnimationManager;
56 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
57 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
58 import com.android.systemui.shared.recents.model.ThumbnailData;
59 import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
60 
61 /**
62  * A utility class which emulates the layout behavior of TaskView and RecentsView
63  */
64 public class TaskViewSimulator implements TransformParams.BuilderProxy {
65 
66     private static final String TAG = "TaskViewSimulator";
67     private static final boolean DEBUG = false;
68 
69     private final Rect mTmpCropRect = new Rect();
70     private final RectF mTempRectF = new RectF();
71     private final float[] mTempPoint = new float[2];
72 
73     private final Context mContext;
74     private final BaseContainerInterface mSizeStrategy;
75 
76     @NonNull
77     private RecentsOrientedState mOrientationState;
78     private final boolean mIsRecentsRtl;
79 
80     private final Rect mTaskRect = new Rect();
81     private final Rect mFullTaskSize = new Rect();
82     private final Rect mCarouselTaskSize = new Rect();
83     private PointF mPivotOverride = null;
84     private final PointF mPivot = new PointF();
85     private DeviceProfile mDp;
86     @StagePosition
87     private int mStagePosition = STAGE_POSITION_UNDEFINED;
88 
89     private final Matrix mMatrix = new Matrix();
90     private final Matrix mMatrixTmp = new Matrix();
91 
92     // Thumbnail view properties
93     private final Rect mThumbnailPosition = new Rect();
94     private final ThumbnailData mThumbnailData = new ThumbnailData();
95     private final PreviewPositionHelper mPositionHelper = new PreviewPositionHelper();
96     private final Matrix mInversePositionMatrix = new Matrix();
97 
98     // TaskView properties
99     private final FullscreenDrawParams mCurrentFullscreenParams;
100     public final AnimatedFloat taskPrimaryTranslation = new AnimatedFloat();
101     public final AnimatedFloat taskSecondaryTranslation = new AnimatedFloat();
102 
103     // Carousel properties
104     public final AnimatedFloat carouselScale = new AnimatedFloat();
105     public final AnimatedFloat carouselPrimaryTranslation = new AnimatedFloat();
106     public final AnimatedFloat carouselSecondaryTranslation = new AnimatedFloat();
107 
108     // RecentsView properties
109     public final AnimatedFloat recentsViewScale = new AnimatedFloat();
110     public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
111     public final AnimatedFloat recentsViewSecondaryTranslation = new AnimatedFloat();
112     public final AnimatedFloat recentsViewPrimaryTranslation = new AnimatedFloat();
113     public final AnimatedFloat recentsViewScroll = new AnimatedFloat();
114 
115     // Cached calculations
116     private boolean mLayoutValid = false;
117     private int mOrientationStateId;
118     private SplitBounds mSplitBounds;
119     private Boolean mDrawsBelowRecents = null;
120     private boolean mIsGridTask;
121     private boolean mIsDesktopTask;
122     private boolean mScaleToCarouselTaskSize = false;
123     private int mTaskRectTranslationX;
124     private int mTaskRectTranslationY;
125 
TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy)126     public TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy) {
127         mContext = context;
128         mSizeStrategy = sizeStrategy;
129 
130         mOrientationState = TraceHelper.allowIpcs("TaskViewSimulator.init",
131                 () -> new RecentsOrientedState(context, sizeStrategy, i -> { }));
132         mOrientationState.setGestureActive(true);
133         mCurrentFullscreenParams = new FullscreenDrawParams(context);
134         mOrientationStateId = mOrientationState.getStateId();
135         Resources resources = context.getResources();
136         mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources);
137         carouselScale.value = 1f;
138     }
139 
140     /**
141      * Sets the device profile for the current state
142      */
setDp(DeviceProfile dp)143     public void setDp(DeviceProfile dp) {
144         mDp = dp;
145         mLayoutValid = false;
146         mOrientationState.setDeviceProfile(dp);
147         calculateTaskSize();
148     }
149 
calculateTaskSize()150     private void calculateTaskSize() {
151         if (mDp == null) {
152             return;
153         }
154 
155         if (mIsGridTask) {
156             mSizeStrategy.calculateGridTaskSize(mContext, mDp, mFullTaskSize,
157                     mOrientationState.getOrientationHandler());
158         } else {
159             mSizeStrategy.calculateTaskSize(mContext, mDp, mFullTaskSize,
160                     mOrientationState.getOrientationHandler());
161         }
162 
163         if (enableGridOnlyOverview()) {
164             mSizeStrategy.calculateCarouselTaskSize(mContext, mDp, mCarouselTaskSize,
165                     mOrientationState.getOrientationHandler());
166         }
167 
168         if (mSplitBounds != null) {
169             // The task rect changes according to the staged split task sizes, but recents
170             // fullscreen scale and pivot remains the same since the task fits into the existing
171             // sized task space bounds
172             mTaskRect.set(mFullTaskSize);
173             mOrientationState.getOrientationHandler()
174                     .setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition);
175             mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
176         } else if (mIsDesktopTask) {
177             // For desktop, tasks can take up only part of the screen size.
178             // Full task size represents the whole screen size, but scaled down to fit in recents.
179             // Task rect will represent the scaled down thumbnail position and is placed inside
180             // full task size as it is on the home screen.
181             PointF fullscreenTaskDimension = new PointF();
182             BaseActivityInterface.getTaskDimension(mContext, mDp, fullscreenTaskDimension);
183             // Calculate the scale down factor used in recents
184             float scale = mFullTaskSize.width() / fullscreenTaskDimension.x;
185             mTaskRect.set(mThumbnailPosition);
186             mTaskRect.scale(scale);
187             // Ensure the task rect is inside the full task rect
188             mTaskRect.offset(mFullTaskSize.left, mFullTaskSize.top);
189         } else {
190             mTaskRect.set(mFullTaskSize);
191             mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
192         }
193     }
194 
195     /**
196      * Sets the orientation state used for this animation
197      */
setOrientationState(@onNull RecentsOrientedState orientationState)198     public void setOrientationState(@NonNull RecentsOrientedState orientationState) {
199         mOrientationState = orientationState;
200         mLayoutValid = false;
201     }
202 
203     /**
204      * @see com.android.quickstep.views.RecentsView#FULLSCREEN_PROGRESS
205      */
getFullScreenScale()206     public float getFullScreenScale() {
207         if (mDp == null) {
208             return 1;
209         }
210         // Copy mFullTaskSize instead of updating it directly so it could be reused next time
211         // without recalculating
212         Rect scaleRect = new Rect();
213         if (mScaleToCarouselTaskSize) {
214             scaleRect.set(mCarouselTaskSize);
215         } else {
216             scaleRect.set(mFullTaskSize);
217         }
218         scaleRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
219         float scale = mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot);
220         if (mPivotOverride != null) {
221             mPivot.set(mPivotOverride);
222         }
223         return scale;
224     }
225 
226     /**
227      * Sets the targets which the simulator will control
228      */
setPreview(RemoteAnimationTarget runningTarget)229     public void setPreview(RemoteAnimationTarget runningTarget) {
230         setPreviewBounds(
231                 runningTarget.startBounds == null
232                         ? runningTarget.screenSpaceBounds : runningTarget.startBounds,
233                 runningTarget.contentInsets);
234     }
235 
236     /**
237      * Sets the targets which the simulator will control specifically for targets to animate when
238      * in split screen
239      *
240      * @param splitInfo set to {@code null} when not in staged split mode
241      */
setPreview(RemoteAnimationTarget runningTarget, SplitBounds splitInfo)242     public void setPreview(RemoteAnimationTarget runningTarget, SplitBounds splitInfo) {
243         setPreview(runningTarget);
244         mSplitBounds = splitInfo;
245         if (mSplitBounds == null) {
246             mStagePosition = STAGE_POSITION_UNDEFINED;
247         } else {
248             mStagePosition = runningTarget.taskId == splitInfo.leftTopTaskId
249                     ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
250             mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
251                     mStagePosition);
252         }
253         calculateTaskSize();
254     }
255 
256     /**
257      * Sets the targets which the simulator will control
258      */
setPreviewBounds(Rect bounds, Rect insets)259     public void setPreviewBounds(Rect bounds, Rect insets) {
260         mThumbnailData.insets.set(insets);
261         // TODO: What is this?
262         mThumbnailData.windowingMode = WINDOWING_MODE_FULLSCREEN;
263 
264         mThumbnailPosition.set(bounds);
265         mLayoutValid = false;
266     }
267 
268     /**
269      * Updates the scroll for RecentsView
270      */
setScroll(float scroll)271     public void setScroll(float scroll) {
272         recentsViewScroll.value = scroll;
273     }
274 
setDrawsBelowRecents(boolean drawsBelowRecents)275     public void setDrawsBelowRecents(boolean drawsBelowRecents) {
276         mDrawsBelowRecents = drawsBelowRecents;
277     }
278 
279     /**
280      * Sets whether the task is part of overview grid and not being focused.
281      */
setIsGridTask(boolean isGridTask)282     public void setIsGridTask(boolean isGridTask) {
283         mIsGridTask = isGridTask;
284     }
285 
286     /**
287      * Sets whether this task is part of desktop tasks in overview.
288      */
setIsDesktopTask(boolean desktop)289     public void setIsDesktopTask(boolean desktop) {
290         mIsDesktopTask = desktop;
291     }
292 
293     /**
294      * Apply translations on TaskRect's starting location.
295      */
setTaskRectTranslation(int taskRectTranslationX, int taskRectTranslationY)296     public void setTaskRectTranslation(int taskRectTranslationX, int taskRectTranslationY) {
297         mTaskRectTranslationX = taskRectTranslationX;
298         mTaskRectTranslationY = taskRectTranslationY;
299         // Re-calculate task size after changing translation
300         calculateTaskSize();
301     }
302 
303     /**
304      * Adds animation for all the components corresponding to transition from an app to overview.
305      */
addAppToOverviewAnim(PendingAnimation pa, Interpolator interpolator)306     public void addAppToOverviewAnim(PendingAnimation pa, Interpolator interpolator) {
307         pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
308         float fullScreenScale;
309         if (enableGridOnlyOverview() && mDp.isTablet && mDp.isGestureMode) {
310             // Move pivot to top right edge of the screen, to avoid task scaling down in opposite
311             // direction of app window movement, otherwise the animation will wiggle left and right.
312             // Also translate the app window to top right edge of the screen to simplify
313             // calculations.
314             taskPrimaryTranslation.value = mIsRecentsRtl
315                     ? mDp.widthPx - mFullTaskSize.right
316                     : -mFullTaskSize.left;
317             taskSecondaryTranslation.value = -mFullTaskSize.top;
318             mPivotOverride = new PointF(mIsRecentsRtl ? mDp.widthPx : 0, 0);
319 
320             // Scale down to the carousel and use the carousel Rect to calculate fullScreenScale.
321             mScaleToCarouselTaskSize = true;
322             carouselScale.value = mCarouselTaskSize.width() / (float) mFullTaskSize.width();
323             fullScreenScale = getFullScreenScale();
324 
325             float carouselPrimaryTranslationTarget = mIsRecentsRtl
326                     ? mCarouselTaskSize.right - mDp.widthPx
327                     : mCarouselTaskSize.left;
328             float carouselSecondaryTranslationTarget = mCarouselTaskSize.top;
329 
330             // Expected carousel position's center is in the middle, and invariant of
331             // recentsViewScale.
332             float exceptedCarouselCenterX = mCarouselTaskSize.centerX();
333             // Animating carousel translations linearly will result in a curved path, therefore
334             // we'll need to calculate the expected translation at each recentsView scale. Luckily
335             // primary and secondary follow the same translation, and primary is used here due to
336             // it being simpler.
337             Interpolator carouselTranslationInterpolator = t -> {
338                 // recentsViewScale is calculated rather than using recentsViewScale.value, so that
339                 // this interpolator works independently even if recentsViewScale don't animate.
340                 float recentsViewScale =
341                         Utilities.mapToRange(t, 0, 1, fullScreenScale, 1, Interpolators.LINEAR);
342                 // Without the translation, the app window will animate from fullscreen into top
343                 // right corner.
344                 float expectedTaskCenterX = mIsRecentsRtl
345                         ? mDp.widthPx - mCarouselTaskSize.width() * recentsViewScale / 2f
346                         : mCarouselTaskSize.width() * recentsViewScale / 2f;
347                 // Calculate the expected translation, then work back the animatedFraction that
348                 // results in this value.
349                 float carouselPrimaryTranslation =
350                         (exceptedCarouselCenterX - expectedTaskCenterX) / recentsViewScale;
351                 return carouselPrimaryTranslation / carouselPrimaryTranslationTarget;
352             };
353 
354             // Use addAnimatedFloat so this animation can later be canceled and animate to a
355             // different value in RecentsView.onPrepareGestureEndAnimation.
356             pa.addAnimatedFloat(carouselPrimaryTranslation, 0, carouselPrimaryTranslationTarget,
357                     carouselTranslationInterpolator);
358             pa.addAnimatedFloat(carouselSecondaryTranslation, 0, carouselSecondaryTranslationTarget,
359                     carouselTranslationInterpolator);
360         } else {
361             fullScreenScale = getFullScreenScale();
362         }
363         pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, fullScreenScale, 1, interpolator);
364     }
365 
366     /**
367      * Adds animation for all the components corresponding to transition from overview to the app.
368      */
addOverviewToAppAnim(PendingAnimation pa, TimeInterpolator interpolator)369     public void addOverviewToAppAnim(PendingAnimation pa, TimeInterpolator interpolator) {
370         pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 0, 1, interpolator);
371         pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, 1, getFullScreenScale(), interpolator);
372     }
373 
374     /**
375      * Returns the current clipped/visible window bounds in the window coordinate space
376      */
getCurrentCropRect()377     public RectF getCurrentCropRect() {
378         // Crop rect is the inverse of thumbnail matrix
379         mTempRectF.set(0, 0, mTaskRect.width(), mTaskRect.height());
380         mInversePositionMatrix.mapRect(mTempRectF);
381         return mTempRectF;
382     }
383 
384     /**
385      * Returns the current task bounds in the Launcher coordinate space.
386      */
getCurrentRect()387     public RectF getCurrentRect() {
388         RectF result = getCurrentCropRect();
389         mMatrixTmp.set(mMatrix);
390         preDisplayRotation(mOrientationState.getDisplayRotation(), mDp.widthPx, mDp.heightPx,
391                 mMatrixTmp);
392         mMatrixTmp.mapRect(result);
393         return result;
394     }
395 
getOrientationState()396     public RecentsOrientedState getOrientationState() {
397         return mOrientationState;
398     }
399 
400     /**
401      * Returns the current transform applied to the window
402      */
getCurrentMatrix()403     public Matrix getCurrentMatrix() {
404         return mMatrix;
405     }
406 
407     /**
408      * Applies the rotation on the matrix to so that it maps from launcher coordinate space to
409      * window coordinate space.
410      */
applyWindowToHomeRotation(Matrix matrix)411     public void applyWindowToHomeRotation(Matrix matrix) {
412         matrix.postTranslate(mDp.windowX, mDp.windowY);
413         postDisplayRotation(deltaRotation(
414                         mOrientationState.getRecentsActivityRotation(),
415                         mOrientationState.getDisplayRotation()),
416                 mDp.widthPx, mDp.heightPx, matrix);
417     }
418 
419     /**
420      * Applies the target to the previously set parameters
421      */
apply(TransformParams params)422     public void apply(TransformParams params) {
423         apply(params, null);
424     }
425 
426     /**
427      * Applies the target to the previously set parameters, optionally with an overridden
428      * surface transaction
429      */
apply(TransformParams params, @Nullable SurfaceTransaction surfaceTransaction)430     public void apply(TransformParams params, @Nullable SurfaceTransaction surfaceTransaction) {
431         if (mDp == null || mThumbnailPosition.isEmpty()) {
432             return;
433         }
434         if (!mLayoutValid || mOrientationStateId != mOrientationState.getStateId()) {
435             mLayoutValid = true;
436             mOrientationStateId = mOrientationState.getStateId();
437 
438             getFullScreenScale();
439             if (TaskAnimationManager.SHELL_TRANSITIONS_ROTATION) {
440                 // With shell transitions, the display is rotated early so we need to actually use
441                 // the rotation when the gesture starts
442                 mThumbnailData.rotation = mOrientationState.getTouchRotation();
443             } else {
444                 mThumbnailData.rotation = mOrientationState.getDisplayRotation();
445             }
446 
447             // mIsRecentsRtl is the inverse of TaskView RTL.
448             boolean isRtlEnabled = !mIsRecentsRtl;
449             mPositionHelper.updateThumbnailMatrix(
450                     mThumbnailPosition, mThumbnailData, mTaskRect.width(), mTaskRect.height(),
451                     mDp.isTablet, mOrientationState.getRecentsActivityRotation(), isRtlEnabled);
452             mPositionHelper.getMatrix().invert(mInversePositionMatrix);
453             if (DEBUG) {
454                 Log.d(TAG, " taskRect: " + mTaskRect);
455             }
456         }
457 
458         float fullScreenProgress = Utilities.boundToRange(this.fullScreenProgress.value, 0, 1);
459         mCurrentFullscreenParams.setProgress(fullScreenProgress, recentsViewScale.value,
460                 carouselScale.value);
461 
462         // Apply thumbnail matrix
463         float taskWidth = mTaskRect.width();
464         float taskHeight = mTaskRect.height();
465 
466         mMatrix.set(mPositionHelper.getMatrix());
467 
468         // Apply TaskView matrix: taskRect, translate
469         mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
470         mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
471                 taskPrimaryTranslation.value);
472         mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
473                 taskSecondaryTranslation.value);
474 
475         mMatrix.postScale(carouselScale.value, carouselScale.value, mPivot.x, mPivot.y);
476         mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
477                 carouselPrimaryTranslation.value);
478         mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
479                 carouselSecondaryTranslation.value);
480 
481         mOrientationState.getOrientationHandler().setPrimary(
482                 mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
483 
484         // Apply RecentsView matrix
485         mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
486         mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
487                 recentsViewSecondaryTranslation.value);
488         mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
489                 recentsViewPrimaryTranslation.value);
490         applyWindowToHomeRotation(mMatrix);
491 
492         // Crop rect is the inverse of thumbnail matrix
493         mTempRectF.set(0, 0, taskWidth, taskHeight);
494         mInversePositionMatrix.mapRect(mTempRectF);
495         mTempRectF.roundOut(mTmpCropRect);
496 
497         params.setProgress(1f - fullScreenProgress);
498         params.applySurfaceParams(surfaceTransaction == null
499                 ? params.createSurfaceParams(this) : surfaceTransaction);
500 
501         if (!DEBUG) {
502             return;
503         }
504         Log.d(TAG, "progress: " + fullScreenProgress
505                 + " carouselScale: " + carouselScale.value
506                 + " recentsViewScale: " + recentsViewScale.value
507                 + " crop: " + mTmpCropRect
508                 + " radius: " + getCurrentCornerRadius()
509                 + " taskW: " + taskWidth + " H: " + taskHeight
510                 + " taskRect: " + mTaskRect
511                 + " taskPrimaryT: " + taskPrimaryTranslation.value
512                 + " taskSecondaryT: " + taskSecondaryTranslation.value
513                 + " carouselPrimaryT: " + carouselPrimaryTranslation.value
514                 + " carouselSecondaryT: " + carouselSecondaryTranslation.value
515                 + " recentsPrimaryT: " + recentsViewPrimaryTranslation.value
516                 + " recentsSecondaryT: " + recentsViewSecondaryTranslation.value
517                 + " recentsScroll: " + recentsViewScroll.value
518                 + " pivot: " + mPivot
519         );
520     }
521 
522     @Override
onBuildTargetParams( SurfaceProperties builder, RemoteAnimationTarget app, TransformParams params)523     public void onBuildTargetParams(
524             SurfaceProperties builder, RemoteAnimationTarget app, TransformParams params) {
525         builder.setMatrix(mMatrix)
526                 .setWindowCrop(mTmpCropRect)
527                 .setCornerRadius(getCurrentCornerRadius());
528 
529         // If mDrawsBelowRecents is unset, no reordering will be enforced.
530         if (mDrawsBelowRecents != null) {
531             // In legacy transitions, the animation leashes remain in same hierarchy in the
532             // TaskDisplayArea, so we don't want to bump the layer too high otherwise it will
533             // conflict with layers that WM core positions (ie. the input consumers).  For shell
534             // transitions, the animation leashes are reparented to an animation container so we
535             // can bump layers as needed.
536             if (ENABLE_SHELL_TRANSITIONS) {
537                 builder.setLayer(mDrawsBelowRecents
538                         ? Integer.MIN_VALUE + app.prefixOrderIndex
539                         // 1000 is an arbitrary number to give room for multiple layers.
540                         : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
541             } else {
542                 builder.setLayer(mDrawsBelowRecents
543                         ? Integer.MIN_VALUE + app.prefixOrderIndex
544                         : 0);
545             }
546         }
547     }
548 
549     /**
550      * Returns the corner radius that should be applied to the target so that it matches the
551      * TaskView
552      */
getCurrentCornerRadius()553     public float getCurrentCornerRadius() {
554         float visibleRadius = mCurrentFullscreenParams.getCurrentDrawnCornerRadius();
555         mTempPoint[0] = visibleRadius;
556         mTempPoint[1] = 0;
557         mInversePositionMatrix.mapVectors(mTempPoint);
558 
559         // Ideally we should use square-root. This is an optimization as one of the dimension is 0.
560         return Math.max(Math.abs(mTempPoint[0]), Math.abs(mTempPoint[1]));
561     }
562 }
563