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