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.util.RecentsOrientedState.postDisplayRotation; 28 import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation; 29 30 import android.animation.TimeInterpolator; 31 import android.content.Context; 32 import android.content.res.Resources; 33 import android.graphics.Matrix; 34 import android.graphics.PointF; 35 import android.graphics.Rect; 36 import android.graphics.RectF; 37 import android.util.Log; 38 import android.view.RemoteAnimationTarget; 39 import android.view.animation.Interpolator; 40 41 import androidx.annotation.NonNull; 42 import androidx.annotation.Nullable; 43 44 import com.android.launcher3.DeviceProfile; 45 import com.android.launcher3.Utilities; 46 import com.android.launcher3.anim.AnimatedFloat; 47 import com.android.launcher3.anim.PendingAnimation; 48 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; 49 import com.android.launcher3.util.TraceHelper; 50 import com.android.quickstep.BaseActivityInterface; 51 import com.android.quickstep.BaseContainerInterface; 52 import com.android.quickstep.DesktopFullscreenDrawParams; 53 import com.android.quickstep.FullscreenDrawParams; 54 import com.android.quickstep.TaskAnimationManager; 55 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; 56 import com.android.systemui.shared.recents.model.ThumbnailData; 57 import com.android.systemui.shared.recents.utilities.PreviewPositionHelper; 58 59 /** 60 * A utility class which emulates the layout behavior of TaskView and RecentsView 61 */ 62 public class TaskViewSimulator implements TransformParams.BuilderProxy { 63 64 private static final String TAG = "TaskViewSimulator"; 65 private static final boolean DEBUG = false; 66 67 private final Rect mTmpCropRect = new Rect(); 68 private final RectF mTempRectF = new RectF(); 69 private final float[] mTempPoint = new float[2]; 70 71 private final Context mContext; 72 private final BaseContainerInterface mSizeStrategy; 73 74 @NonNull 75 private RecentsOrientedState mOrientationState; 76 private final boolean mIsRecentsRtl; 77 78 private final Rect mTaskRect = new Rect(); 79 private final Rect mFullTaskSize = new Rect(); 80 private final Rect mCarouselTaskSize = new Rect(); 81 private PointF mPivotOverride = null; 82 private final PointF mPivot = new PointF(); 83 private DeviceProfile mDp; 84 @StagePosition 85 private int mStagePosition = STAGE_POSITION_UNDEFINED; 86 87 private final Matrix mMatrix = new Matrix(); 88 private final Matrix mMatrixTmp = new Matrix(); 89 90 // Thumbnail view properties 91 private final Rect mThumbnailPosition = new Rect(); 92 private final ThumbnailData mThumbnailData = new ThumbnailData(); 93 private final PreviewPositionHelper mPositionHelper = new PreviewPositionHelper(); 94 private final Matrix mInversePositionMatrix = new Matrix(); 95 96 // TaskView properties 97 private final FullscreenDrawParams mCurrentFullscreenParams; 98 public final AnimatedFloat taskPrimaryTranslation = new AnimatedFloat(); 99 public final AnimatedFloat taskSecondaryTranslation = new AnimatedFloat(); 100 public final AnimatedFloat taskGridTranslationX = new AnimatedFloat(); 101 public final AnimatedFloat taskGridTranslationY = new AnimatedFloat(); 102 103 // Carousel properties 104 public final AnimatedFloat carouselScale = new AnimatedFloat(); 105 106 // RecentsView properties 107 public final AnimatedFloat recentsViewScale = new AnimatedFloat(); 108 public final AnimatedFloat fullScreenProgress = new AnimatedFloat(); 109 public final AnimatedFloat recentsViewSecondaryTranslation = new AnimatedFloat(); 110 public final AnimatedFloat recentsViewPrimaryTranslation = new AnimatedFloat(); 111 public final AnimatedFloat recentsViewScroll = new AnimatedFloat(); 112 113 // Cached calculations 114 private boolean mLayoutValid = false; 115 private int mOrientationStateId; 116 private SplitBounds mSplitBounds; 117 private Boolean mDrawsBelowRecents = null; 118 private boolean mIsGridTask; 119 private final boolean mIsDesktopTask; 120 private boolean mIsAnimatingToCarousel = false; 121 private int mTaskRectTranslationX; 122 private int mTaskRectTranslationY; 123 private int mDesktopTaskIndex = 0; 124 125 @Nullable 126 private Matrix mTaskRectTransform = null; 127 TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy, boolean isDesktop, int desktopTaskIndex)128 public TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy, 129 boolean isDesktop, int desktopTaskIndex) { 130 mContext = context; 131 mSizeStrategy = sizeStrategy; 132 mIsDesktopTask = isDesktop; 133 mDesktopTaskIndex = desktopTaskIndex; 134 135 mOrientationState = TraceHelper.allowIpcs("TaskViewSimulator.init", 136 () -> new RecentsOrientedState(context, sizeStrategy, i -> { })); 137 mOrientationState.setGestureActive(true); 138 mCurrentFullscreenParams = mIsDesktopTask 139 ? new DesktopFullscreenDrawParams(context) 140 : new FullscreenDrawParams(context); 141 mOrientationStateId = mOrientationState.getStateId(); 142 Resources resources = context.getResources(); 143 mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources); 144 carouselScale.value = 1f; 145 } 146 147 /** 148 * Sets the device profile for the current state 149 */ setDp(DeviceProfile dp)150 public void setDp(DeviceProfile dp) { 151 mDp = dp; 152 mLayoutValid = false; 153 mOrientationState.setDeviceProfile(dp); 154 if (enableGridOnlyOverview()) { 155 mIsGridTask = dp.isTablet && !mIsDesktopTask; 156 } 157 calculateTaskSize(); 158 } 159 calculateTaskSize()160 private void calculateTaskSize() { 161 if (mDp == null) { 162 return; 163 } 164 165 if (mIsGridTask) { 166 mSizeStrategy.calculateGridTaskSize(mContext, mDp, mFullTaskSize, 167 mOrientationState.getOrientationHandler()); 168 if (enableGridOnlyOverview()) { 169 mSizeStrategy.calculateTaskSize(mContext, mDp, mCarouselTaskSize, 170 mOrientationState.getOrientationHandler()); 171 } 172 } else { 173 mSizeStrategy.calculateTaskSize(mContext, mDp, mFullTaskSize, 174 mOrientationState.getOrientationHandler()); 175 if (enableGridOnlyOverview()) { 176 mCarouselTaskSize.set(mFullTaskSize); 177 } 178 } 179 180 if (mSplitBounds != null) { 181 // The task rect changes according to the staged split task sizes, but recents 182 // fullscreen scale and pivot remains the same since the task fits into the existing 183 // sized task space bounds 184 mTaskRect.set(mFullTaskSize); 185 mOrientationState.getOrientationHandler() 186 .setSplitTaskSwipeRect(mDp, mTaskRect, mSplitBounds, mStagePosition); 187 } else if (mIsDesktopTask) { 188 // For desktop, tasks can take up only part of the screen size. 189 // Full task size represents the whole screen size, but scaled down to fit in recents. 190 // Task rect will represent the scaled down thumbnail position and is placed inside 191 // full task size as it is on the home screen. 192 PointF fullscreenTaskDimension = new PointF(); 193 BaseActivityInterface.getTaskDimension(mContext, mDp, fullscreenTaskDimension); 194 // Calculate the scale down factor used in recents 195 float scale = mFullTaskSize.width() / fullscreenTaskDimension.x; 196 mTaskRect.set(mThumbnailPosition); 197 mTaskRect.scale(scale); 198 // Ensure the task rect is inside the full task rect 199 mTaskRect.offset(mFullTaskSize.left, mFullTaskSize.top); 200 201 Rect taskDimension = new Rect(0, 0, (int) fullscreenTaskDimension.x, 202 (int) fullscreenTaskDimension.y); 203 mTmpCropRect.set(mThumbnailPosition); 204 if (mTmpCropRect.setIntersect(taskDimension, mThumbnailPosition)) { 205 mTmpCropRect.offset(-mThumbnailPosition.left, -mThumbnailPosition.top); 206 } else { 207 mTmpCropRect.setEmpty(); 208 } 209 } else { 210 mTaskRect.set(mFullTaskSize); 211 } 212 mTaskRect.offset(mTaskRectTranslationX, mTaskRectTranslationY); 213 } 214 215 /** 216 * Sets the orientation state used for this animation 217 */ setOrientationState(@onNull RecentsOrientedState orientationState)218 public void setOrientationState(@NonNull RecentsOrientedState orientationState) { 219 mOrientationState = orientationState; 220 mLayoutValid = false; 221 } 222 223 /** 224 * @see com.android.quickstep.views.RecentsView#FULLSCREEN_PROGRESS 225 */ getFullScreenScale()226 public float getFullScreenScale() { 227 if (mDp == null) { 228 return 1; 229 } 230 // Copy mFullTaskSize instead of updating it directly so it could be reused next time 231 // without recalculating 232 Rect scaleRect = new Rect(mIsAnimatingToCarousel ? mCarouselTaskSize : mFullTaskSize); 233 scaleRect.offset(mTaskRectTranslationX, mTaskRectTranslationY); 234 float scale = mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot); 235 if (mPivotOverride != null) { 236 mPivot.set(mPivotOverride); 237 } 238 return scale; 239 } 240 241 /** 242 * Sets the targets which the simulator will control 243 */ setPreview(RemoteAnimationTarget runningTarget)244 public void setPreview(RemoteAnimationTarget runningTarget) { 245 setPreviewBounds( 246 runningTarget.startBounds == null 247 ? runningTarget.screenSpaceBounds : runningTarget.startBounds, 248 runningTarget.contentInsets); 249 } 250 251 /** 252 * Sets the targets which the simulator will control specifically for targets to animate when 253 * in split screen 254 * 255 * @param splitInfo set to {@code null} when not in staged split mode 256 */ setPreview(RemoteAnimationTarget runningTarget, SplitBounds splitInfo)257 public void setPreview(RemoteAnimationTarget runningTarget, SplitBounds splitInfo) { 258 setPreview(runningTarget); 259 mSplitBounds = splitInfo; 260 if (mSplitBounds == null) { 261 mStagePosition = STAGE_POSITION_UNDEFINED; 262 } else { 263 mStagePosition = runningTarget.taskId == splitInfo.leftTopTaskId 264 ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT; 265 } 266 calculateTaskSize(); 267 } 268 269 /** 270 * Sets the targets which the simulator will control 271 */ setPreviewBounds(Rect bounds, Rect insets)272 public void setPreviewBounds(Rect bounds, Rect insets) { 273 mThumbnailData.insets.set(insets); 274 // TODO: What is this? 275 mThumbnailData.windowingMode = WINDOWING_MODE_FULLSCREEN; 276 277 mThumbnailPosition.set(bounds); 278 mLayoutValid = false; 279 } 280 281 /** 282 * Updates the scroll for RecentsView 283 */ setScroll(float scroll)284 public void setScroll(float scroll) { 285 recentsViewScroll.value = scroll; 286 } 287 setDrawsBelowRecents(boolean drawsBelowRecents)288 public void setDrawsBelowRecents(boolean drawsBelowRecents) { 289 mDrawsBelowRecents = drawsBelowRecents; 290 } 291 292 /** 293 * Sets whether the task is part of overview grid and not being focused. 294 */ setIsGridTask(boolean isGridTask)295 public void setIsGridTask(boolean isGridTask) { 296 mIsGridTask = isGridTask; 297 } 298 299 /** 300 * Apply translations on TaskRect's starting location. 301 */ setTaskRectTranslation(int taskRectTranslationX, int taskRectTranslationY)302 public void setTaskRectTranslation(int taskRectTranslationX, int taskRectTranslationY) { 303 mTaskRectTranslationX = taskRectTranslationX; 304 mTaskRectTranslationY = taskRectTranslationY; 305 // Re-calculate task size after changing translation 306 calculateTaskSize(); 307 } 308 309 /** 310 * Override the pivot used to apply scale changes. 311 */ setPivotOverride(PointF pivotOverride)312 public void setPivotOverride(PointF pivotOverride) { 313 mPivotOverride = pivotOverride; 314 getFullScreenScale(); 315 } 316 317 /** 318 * Adds animation for all the components corresponding to transition from an app to carousel. 319 */ addAppToCarouselAnim(PendingAnimation pa, Interpolator interpolator)320 public void addAppToCarouselAnim(PendingAnimation pa, Interpolator interpolator) { 321 pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator); 322 if (enableGridOnlyOverview() && mDp.isTablet && mDp.isGestureMode) { 323 mIsAnimatingToCarousel = true; 324 carouselScale.value = mCarouselTaskSize.width() / (float) mFullTaskSize.width(); 325 } 326 pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, getFullScreenScale(), 1, 327 interpolator); 328 } 329 330 /** 331 * Adds animation for all the components corresponding to transition from overview to the app. 332 */ addOverviewToAppAnim(PendingAnimation pa, TimeInterpolator interpolator)333 public void addOverviewToAppAnim(PendingAnimation pa, TimeInterpolator interpolator) { 334 pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 0, 1, interpolator); 335 pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, 1, getFullScreenScale(), interpolator); 336 } 337 338 /** 339 * Returns the current clipped/visible window bounds in the window coordinate space 340 */ getCurrentCropRect()341 public RectF getCurrentCropRect() { 342 // Crop rect is the inverse of thumbnail matrix 343 mTempRectF.set(0, 0, mTaskRect.width(), mTaskRect.height()); 344 mInversePositionMatrix.mapRect(mTempRectF); 345 return mTempRectF; 346 } 347 348 /** 349 * Returns the current task bounds in the Launcher coordinate space. 350 */ getCurrentRect()351 public RectF getCurrentRect() { 352 RectF result = getCurrentCropRect(); 353 mMatrixTmp.set(mMatrix); 354 preDisplayRotation(mOrientationState.getDisplayRotation(), mDp.widthPx, mDp.heightPx, 355 mMatrixTmp); 356 mMatrixTmp.mapRect(result); 357 return result; 358 } 359 getOrientationState()360 public RecentsOrientedState getOrientationState() { 361 return mOrientationState; 362 } 363 364 /** 365 * Returns the current transform applied to the window 366 */ getCurrentMatrix()367 public Matrix getCurrentMatrix() { 368 return mMatrix; 369 } 370 371 /** 372 * Sets a matrix used to transform the position of tasks. If set, this matrix is applied to 373 * the task rect after the task has been scaled and positioned inside the fulltask, but 374 * before scaling and translation of the whole recents view is performed. 375 */ setTaskRectTransform(@ullable Matrix taskRectTransform)376 public void setTaskRectTransform(@Nullable Matrix taskRectTransform) { 377 mTaskRectTransform = taskRectTransform; 378 } 379 380 /** 381 * Calculates the crop rect for desktop tasks given the current matrix. 382 */ calculateDesktopTaskCropRect()383 private void calculateDesktopTaskCropRect() { 384 // The approach here is to map a rect that represents the untransformed thumbnail position 385 // using the current matrix. This will give us a rect that can be intersected with 386 // [mFullTaskSize]. Using the intersection, we then compute how much of the task window that 387 // needs to be cropped (which will be nothing if the window is entirely within the desktop). 388 mTempRectF.set(0, 0, mThumbnailPosition.width(), mThumbnailPosition.height()); 389 mMatrix.mapRect(mTempRectF); 390 391 float offsetX = mTempRectF.left; 392 float offsetY = mTempRectF.top; 393 float scale = mThumbnailPosition.width() / mTempRectF.width(); 394 395 if (mTempRectF.intersect(mFullTaskSize.left, mFullTaskSize.top, mFullTaskSize.right, 396 mFullTaskSize.bottom)) { 397 mTempRectF.offset(-offsetX, -offsetY); 398 mTempRectF.scale(scale); 399 mTempRectF.round(mTmpCropRect); 400 } 401 } 402 403 /** 404 * Applies the rotation on the matrix to so that it maps from launcher coordinate space to 405 * window coordinate space. 406 */ applyWindowToHomeRotation(Matrix matrix)407 public void applyWindowToHomeRotation(Matrix matrix) { 408 matrix.postTranslate(mDp.windowX, mDp.windowY); 409 postDisplayRotation(deltaRotation( 410 mOrientationState.getRecentsActivityRotation(), 411 mOrientationState.getDisplayRotation()), 412 mDp.widthPx, mDp.heightPx, matrix); 413 } 414 415 /** 416 * Applies the target to the previously set parameters 417 */ apply(TransformParams params)418 public void apply(TransformParams params) { 419 apply(params, null); 420 } 421 422 /** 423 * Applies the target to the previously set parameters, optionally with an overridden 424 * surface transaction 425 */ apply(TransformParams params, @Nullable SurfaceTransaction surfaceTransaction)426 public void apply(TransformParams params, @Nullable SurfaceTransaction surfaceTransaction) { 427 if (mDp == null || mThumbnailPosition.isEmpty()) { 428 return; 429 } 430 if (!mLayoutValid || mOrientationStateId != mOrientationState.getStateId()) { 431 mLayoutValid = true; 432 mOrientationStateId = mOrientationState.getStateId(); 433 434 getFullScreenScale(); 435 if (TaskAnimationManager.SHELL_TRANSITIONS_ROTATION) { 436 // With shell transitions, the display is rotated early so we need to actually use 437 // the rotation when the gesture starts 438 mThumbnailData.rotation = mOrientationState.getTouchRotation(); 439 } else { 440 mThumbnailData.rotation = mOrientationState.getDisplayRotation(); 441 } 442 443 // mIsRecentsRtl is the inverse of TaskView RTL. 444 boolean isRtlEnabled = !mIsRecentsRtl; 445 mPositionHelper.updateThumbnailMatrix( 446 mThumbnailPosition, mThumbnailData, mTaskRect.width(), mTaskRect.height(), 447 mDp.isTablet, mOrientationState.getRecentsActivityRotation(), isRtlEnabled); 448 mPositionHelper.getMatrix().invert(mInversePositionMatrix); 449 if (DEBUG) { 450 Log.d(TAG, " taskRect: " + mTaskRect); 451 } 452 } 453 454 float fullScreenProgress = Utilities.boundToRange(this.fullScreenProgress.value, 0, 1); 455 mCurrentFullscreenParams.setProgress(fullScreenProgress, recentsViewScale.value, 456 carouselScale.value); 457 458 // Apply thumbnail matrix 459 float taskWidth = mTaskRect.width(); 460 float taskHeight = mTaskRect.height(); 461 462 mMatrix.set(mPositionHelper.getMatrix()); 463 464 // Apply TaskView matrix: taskRect, optional transform, translate 465 mMatrix.postTranslate(mTaskRect.left, mTaskRect.top); 466 if (mTaskRectTransform != null) { 467 mMatrix.postConcat(mTaskRectTransform); 468 469 // Calculate cropping for desktop tasks. The order is important since it uses the 470 // current matrix. Therefore we calculate it here, after applying the task rect 471 // transform, but before applying scaling/translation that affects the whole 472 // recentsview. 473 if (mIsDesktopTask) { 474 calculateDesktopTaskCropRect(); 475 } 476 } 477 478 mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE, 479 taskPrimaryTranslation.value); 480 mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE, 481 taskSecondaryTranslation.value); 482 mMatrix.postTranslate(taskGridTranslationX.value, taskGridTranslationY.value); 483 484 mMatrix.postScale(carouselScale.value, carouselScale.value, 485 mIsRecentsRtl ? mCarouselTaskSize.right : mCarouselTaskSize.left, 486 mCarouselTaskSize.top); 487 488 mOrientationState.getOrientationHandler().setPrimary( 489 mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value); 490 491 // Apply RecentsView matrix 492 mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y); 493 mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE, 494 recentsViewSecondaryTranslation.value); 495 mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE, 496 recentsViewPrimaryTranslation.value); 497 applyWindowToHomeRotation(mMatrix); 498 499 if (!mIsDesktopTask) { 500 // Crop rect is the inverse of thumbnail matrix 501 mTempRectF.set(0, 0, taskWidth, taskHeight); 502 mInversePositionMatrix.mapRect(mTempRectF); 503 mTempRectF.roundOut(mTmpCropRect); 504 } 505 506 params.setProgress(1f - fullScreenProgress); 507 params.applySurfaceParams(surfaceTransaction == null 508 ? params.createSurfaceParams(this) : surfaceTransaction); 509 510 if (!DEBUG) { 511 return; 512 } 513 Log.d(TAG, "progress: " + fullScreenProgress 514 + " carouselScale: " + carouselScale.value 515 + " recentsViewScale: " + recentsViewScale.value 516 + " crop: " + mTmpCropRect 517 + " radius: " + getCurrentCornerRadius() 518 + " taskW: " + taskWidth + " H: " + taskHeight 519 + " taskRect: " + mTaskRect 520 + " taskPrimaryT: " + taskPrimaryTranslation.value 521 + " taskSecondaryT: " + taskSecondaryTranslation.value 522 + " taskGridTranslationX: " + taskGridTranslationX.value 523 + " taskGridTranslationY: " + taskGridTranslationY.value 524 + " recentsPrimaryT: " + recentsViewPrimaryTranslation.value 525 + " recentsSecondaryT: " + recentsViewSecondaryTranslation.value 526 + " recentsScroll: " + recentsViewScroll.value 527 + " pivot: " + mPivot 528 ); 529 } 530 531 @Override onBuildTargetParams( SurfaceProperties builder, RemoteAnimationTarget app, TransformParams params)532 public void onBuildTargetParams( 533 SurfaceProperties builder, RemoteAnimationTarget app, TransformParams params) { 534 builder.setMatrix(mMatrix) 535 .setWindowCrop(mTmpCropRect) 536 .setCornerRadius(getCurrentCornerRadius()); 537 538 // If mDrawsBelowRecents is unset, no reordering will be enforced. 539 if (mDrawsBelowRecents != null) { 540 // In shell transitions, the animation leashes are reparented to an animation container 541 // so we can bump layers as needed. 542 builder.setLayer(mDrawsBelowRecents 543 // 1000 is an arbitrary number to give room for multiple layers. 544 ? Integer.MIN_VALUE + 1000 + app.prefixOrderIndex - mDesktopTaskIndex 545 : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex - mDesktopTaskIndex); 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.getCurrentCornerRadius(); 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