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; 17 18 import static com.android.app.animation.Interpolators.ACCELERATE_1_5; 19 import static com.android.app.animation.Interpolators.LINEAR; 20 import static com.android.launcher3.Flags.enableAdditionalHomeAnimations; 21 import static com.android.launcher3.PagedView.INVALID_PAGE; 22 23 import android.animation.Animator; 24 import android.content.Context; 25 import android.graphics.Matrix; 26 import android.graphics.Matrix.ScaleToFit; 27 import android.graphics.Rect; 28 import android.graphics.RectF; 29 import android.view.RemoteAnimationTarget; 30 31 import androidx.annotation.NonNull; 32 import androidx.annotation.Nullable; 33 import androidx.annotation.UiThread; 34 35 import com.android.launcher3.DeviceProfile; 36 import com.android.launcher3.Utilities; 37 import com.android.launcher3.anim.AnimatedFloat; 38 import com.android.launcher3.anim.AnimationSuccessListener; 39 import com.android.launcher3.anim.AnimatorPlaybackController; 40 import com.android.launcher3.anim.PendingAnimation; 41 import com.android.launcher3.touch.PagedOrientationHandler; 42 import com.android.launcher3.views.ClipIconView; 43 import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle; 44 import com.android.quickstep.orientation.RecentsPagedOrientationHandler; 45 import com.android.quickstep.util.AnimatorControllerWithResistance; 46 import com.android.quickstep.util.RectFSpringAnim; 47 import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig; 48 import com.android.quickstep.util.RectFSpringAnim.TaskbarHotseatSpringConfig; 49 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties; 50 import com.android.quickstep.util.TaskViewSimulator; 51 import com.android.quickstep.util.TransformParams; 52 import com.android.quickstep.util.TransformParams.BuilderProxy; 53 import com.android.quickstep.views.RecentsView; 54 import com.android.quickstep.views.TaskView; 55 56 import java.util.Arrays; 57 import java.util.function.Consumer; 58 59 public abstract class SwipeUpAnimationLogic implements 60 RecentsAnimationCallbacks.RecentsAnimationListener{ 61 62 protected static final Rect TEMP_RECT = new Rect(); 63 protected final RemoteTargetGluer mTargetGluer; 64 65 protected DeviceProfile mDp; 66 67 protected final Context mContext; 68 protected final RecentsAnimationDeviceState mDeviceState; 69 protected final GestureState mGestureState; 70 71 protected RemoteTargetHandle[] mRemoteTargetHandles; 72 73 // Shift in the range of [0, 1]. 74 // 0 => preview snapShot is completely visible, and hotseat is completely translated down 75 // 1 => preview snapShot is completely aligned with the recents view and hotseat is completely 76 // visible. 77 protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::onCurrentShiftUpdated); 78 protected float mCurrentDisplacement; 79 80 // The distance needed to drag to reach the task size in recents. 81 protected int mTransitionDragLength; 82 // How much further we can drag past recents, as a factor of mTransitionDragLength. 83 protected float mDragLengthFactor = 1; 84 85 protected boolean mIsSwipeForSplit; 86 SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState, GestureState gestureState)87 public SwipeUpAnimationLogic(Context context, RecentsAnimationDeviceState deviceState, 88 GestureState gestureState) { 89 mContext = context; 90 mDeviceState = deviceState; 91 mGestureState = gestureState; 92 updateIsGestureForSplit(TopTaskTracker.INSTANCE.get(context) 93 .getRunningSplitTaskIds().length); 94 95 mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getContainerInterface()); 96 mRemoteTargetHandles = mTargetGluer.getRemoteTargetHandles(); 97 runActionOnRemoteHandles(remoteTargetHandle -> 98 remoteTargetHandle.getTaskViewSimulator().getOrientationState().update( 99 mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(), 100 mDeviceState.getRotationTouchHelper().getDisplayRotation() 101 )); 102 } 103 initTransitionEndpoints(DeviceProfile dp)104 protected void initTransitionEndpoints(DeviceProfile dp) { 105 mDp = dp; 106 mTransitionDragLength = mGestureState.getContainerInterface() 107 .getSwipeUpDestinationAndLength(dp, mContext, TEMP_RECT, 108 mRemoteTargetHandles[0].getTaskViewSimulator().getOrientationState() 109 .getOrientationHandler()); 110 mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength; 111 112 for (RemoteTargetHandle remoteHandle : mRemoteTargetHandles) { 113 PendingAnimation pendingAnimation = new PendingAnimation(mTransitionDragLength * 2); 114 TaskViewSimulator taskViewSimulator = remoteHandle.getTaskViewSimulator(); 115 taskViewSimulator.setDp(dp); 116 taskViewSimulator.addAppToOverviewAnim(pendingAnimation, LINEAR); 117 AnimatorPlaybackController playbackController = 118 pendingAnimation.createPlaybackController(); 119 120 remoteHandle.setPlaybackController(AnimatorControllerWithResistance.createForRecents( 121 playbackController, mContext, taskViewSimulator.getOrientationState(), 122 mDp, taskViewSimulator.recentsViewScale, AnimatedFloat.VALUE, 123 taskViewSimulator.recentsViewSecondaryTranslation, AnimatedFloat.VALUE 124 )); 125 } 126 } 127 128 @UiThread updateDisplacement(float displacement)129 public void updateDisplacement(float displacement) { 130 // We are moving in the negative x/y direction 131 displacement = overrideDisplacementForTransientTaskbar(-displacement); 132 mCurrentDisplacement = displacement; 133 134 float shift; 135 if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) { 136 shift = mDragLengthFactor; 137 } else { 138 float translation = Math.max(displacement, 0); 139 shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength; 140 } 141 142 mCurrentShift.updateValue(shift); 143 } 144 145 /** 146 * When Transient Taskbar is enabled, subclasses can override the displacement to keep the app 147 * window at the bottom of the screen while taskbar is being swiped in. 148 * @param displacement The distance the user has swiped up from the bottom of the screen. This 149 * value will be positive unless the user swipe downwards. 150 * @return the overridden displacement. 151 */ overrideDisplacementForTransientTaskbar(float displacement)152 protected float overrideDisplacementForTransientTaskbar(float displacement) { 153 return displacement; 154 } 155 156 /** 157 * Called when the value of {@link #mCurrentShift} changes 158 */ 159 @UiThread onCurrentShiftUpdated()160 public abstract void onCurrentShiftUpdated(); 161 getOrientationHandler()162 protected RecentsPagedOrientationHandler getOrientationHandler() { 163 // OrientationHandler should be independent of remote target, can directly take one 164 return mRemoteTargetHandles[0].getTaskViewSimulator() 165 .getOrientationState().getOrientationHandler(); 166 } 167 168 protected abstract class HomeAnimationFactory { 169 protected float mSwipeVelocity; 170 171 /** 172 * Returns true if we know the home animation involves an item in the hotseat. 173 */ isInHotseat()174 public boolean isInHotseat() { 175 return false; 176 } 177 getWindowTargetRect()178 public @NonNull RectF getWindowTargetRect() { 179 PagedOrientationHandler orientationHandler = getOrientationHandler(); 180 DeviceProfile dp = mDp; 181 final int halfIconSize = dp.iconSizePx / 2; 182 float primaryDimension = orientationHandler 183 .getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx); 184 float secondaryDimension = orientationHandler 185 .getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx); 186 final float targetX = primaryDimension / 2f; 187 final float targetY = secondaryDimension - dp.hotseatBarSizePx; 188 // Fallback to animate to center of screen. 189 return new RectF(targetX - halfIconSize, targetY - halfIconSize, 190 targetX + halfIconSize, targetY + halfIconSize); 191 } 192 193 /** Returns the corner radius of the window at the end of the animation. */ getEndRadius(RectF cropRectF)194 public float getEndRadius(RectF cropRectF) { 195 return cropRectF.width() / 2f; 196 } 197 createActivityAnimationToHome()198 public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome(); 199 setSwipeVelocity(float velocity)200 public void setSwipeVelocity(float velocity) { 201 mSwipeVelocity = velocity; 202 } 203 playAtomicAnimation(float velocity)204 public void playAtomicAnimation(float velocity) { 205 // No-op 206 } 207 setAnimation(RectFSpringAnim anim)208 public void setAnimation(RectFSpringAnim anim) { } 209 update(RectF currentRect, float progress, float radius, int overlayAlpha)210 public void update(RectF currentRect, float progress, float radius, int overlayAlpha) { } 211 onCancel()212 public void onCancel() { } 213 214 /** 215 * @param progress The progress of the animation to the home screen. 216 * @return The current alpha to set on the animating app window. 217 */ getWindowAlpha(float progress)218 protected float getWindowAlpha(float progress) { 219 // Alpha interpolates between [1, 0] between progress values [start, end] 220 final float start = 0f; 221 final float end = 0.85f; 222 223 if (progress <= start) { 224 return 1f; 225 } 226 if (progress >= end) { 227 return 0f; 228 } 229 return Utilities.mapToRange(progress, start, end, 1, 0, ACCELERATE_1_5); 230 } 231 232 /** 233 * Sets a {@link com.android.launcher3.views.ClipIconView.TaskViewArtist} that should be 234 * used draw a {@link TaskView} during this home animation. 235 */ setTaskViewArtist(ClipIconView.TaskViewArtist taskViewArtist)236 public void setTaskViewArtist(ClipIconView.TaskViewArtist taskViewArtist) { } 237 isAnimationReady()238 public boolean isAnimationReady() { 239 return true; 240 } 241 isAnimatingIntoIcon()242 public boolean isAnimatingIntoIcon() { 243 return false; 244 } 245 246 @Nullable getTargetTaskView()247 public TaskView getTargetTaskView() { 248 return null; 249 } 250 isRtl()251 public boolean isRtl() { 252 return Utilities.isRtl(mContext.getResources()); 253 } 254 isPortrait()255 public boolean isPortrait() { 256 return !mDp.isLandscape && !mDp.isSeascape(); 257 } 258 } 259 260 /** 261 * Update with start progress for window animation to home. 262 * @param outMatrix {@link Matrix} to map a rect in Launcher space to window space. 263 * @param startProgress The progress of {@link #mCurrentShift} to start thw window from. 264 * @return {@link RectF} represents the bounds as starting point in window space. 265 */ updateProgressForStartRect(Matrix[] outMatrix, float startProgress)266 protected RectF[] updateProgressForStartRect(Matrix[] outMatrix, float startProgress) { 267 mCurrentShift.updateValue(startProgress); 268 RectF[] startRects = new RectF[mRemoteTargetHandles.length]; 269 for (int i = 0, mRemoteTargetHandlesLength = mRemoteTargetHandles.length; 270 i < mRemoteTargetHandlesLength; i++) { 271 RemoteTargetHandle remoteHandle = mRemoteTargetHandles[i]; 272 TaskViewSimulator tvs = remoteHandle.getTaskViewSimulator(); 273 tvs.apply(remoteHandle.getTransformParams().setProgress(startProgress)); 274 275 startRects[i] = new RectF(tvs.getCurrentCropRect()); 276 outMatrix[i] = new Matrix(); 277 tvs.applyWindowToHomeRotation(outMatrix[i]); 278 tvs.getCurrentMatrix().mapRect(startRects[i]); 279 } 280 return startRects; 281 } 282 283 /** Helper to avoid writing some for-loops to iterate over {@link #mRemoteTargetHandles} */ runActionOnRemoteHandles(Consumer<RemoteTargetHandle> consumer)284 protected void runActionOnRemoteHandles(Consumer<RemoteTargetHandle> consumer) { 285 for (RemoteTargetHandle handle : mRemoteTargetHandles) { 286 consumer.accept(handle); 287 } 288 } 289 290 /** @return only the TaskViewSimulators from {@link #mRemoteTargetHandles} */ getRemoteTaskViewSimulators()291 protected TaskViewSimulator[] getRemoteTaskViewSimulators() { 292 return Arrays.stream(mRemoteTargetHandles) 293 .map(remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()) 294 .toArray(TaskViewSimulator[]::new); 295 } 296 297 /** 298 * Creates an animation that transforms the current app window into the home app. 299 * @param startProgress The progress of {@link #mCurrentShift} to start the window from. 300 * @param homeAnimationFactory The home animation factory. 301 */ createWindowAnimationToHome(float startProgress, HomeAnimationFactory homeAnimationFactory)302 protected RectFSpringAnim[] createWindowAnimationToHome(float startProgress, 303 HomeAnimationFactory homeAnimationFactory) { 304 // TODO(b/195473584) compute separate end targets for different staged split 305 final RectF targetRect = homeAnimationFactory.getWindowTargetRect(); 306 RectFSpringAnim[] out = new RectFSpringAnim[mRemoteTargetHandles.length]; 307 Matrix[] homeToWindowPositionMap = new Matrix[mRemoteTargetHandles.length]; 308 RectF[] startRects = updateProgressForStartRect(homeToWindowPositionMap, startProgress); 309 for (int i = 0, mRemoteTargetHandlesLength = mRemoteTargetHandles.length; 310 i < mRemoteTargetHandlesLength; i++) { 311 RemoteTargetHandle remoteHandle = mRemoteTargetHandles[i]; 312 out[i] = getWindowAnimationToHomeInternal( 313 homeAnimationFactory, 314 targetRect, 315 remoteHandle.getTransformParams(), 316 remoteHandle.getTaskViewSimulator(), 317 startRects[i], 318 homeToWindowPositionMap[i]); 319 } 320 return out; 321 } 322 updateIsGestureForSplit(int targetCount)323 protected void updateIsGestureForSplit(int targetCount) { 324 mIsSwipeForSplit = targetCount > 1; 325 } 326 getWindowAnimationToHomeInternal( HomeAnimationFactory homeAnimationFactory, RectF targetRect, TransformParams transformParams, TaskViewSimulator taskViewSimulator, RectF startRect, Matrix homeToWindowPositionMap)327 private RectFSpringAnim getWindowAnimationToHomeInternal( 328 HomeAnimationFactory homeAnimationFactory, 329 RectF targetRect, 330 TransformParams transformParams, 331 TaskViewSimulator taskViewSimulator, 332 RectF startRect, 333 Matrix homeToWindowPositionMap) { 334 RectF cropRectF = new RectF(taskViewSimulator.getCurrentCropRect()); 335 // Move the startRect to Launcher space as floatingIconView runs in Launcher 336 Matrix windowToHomePositionMap = new Matrix(); 337 338 TaskView targetTaskView = homeAnimationFactory.getTargetTaskView(); 339 if (targetTaskView == null) { 340 // If the start rect ends up overshooting too much to the left/right offscreen, bring it 341 // back to fullscreen. This can happen when the recentsScroll value isn't aligned with 342 // the pageScroll value for a given taskView, see b/228829958#comment12 343 mRemoteTargetHandles[0].getTaskViewSimulator() 344 .getOrientationState() 345 .getOrientationHandler() 346 .fixBoundsForHomeAnimStartRect(startRect, mDp); 347 348 } 349 homeToWindowPositionMap.invert(windowToHomePositionMap); 350 windowToHomePositionMap.mapRect(startRect); 351 RectF invariantStartRect = new RectF(startRect); 352 353 if (targetTaskView != null) { 354 Rect thumbnailBounds = new Rect(); 355 targetTaskView.getThumbnailBounds(thumbnailBounds, /* relativeToDragLayer= */ true); 356 357 invariantStartRect = new RectF(thumbnailBounds); 358 invariantStartRect.offsetTo(startRect.left, thumbnailBounds.top); 359 startRect = new RectF(thumbnailBounds); 360 } 361 362 boolean useTaskbarHotseatParams = mDp.isTaskbarPresent 363 && homeAnimationFactory.isInHotseat(); 364 RectFSpringAnim anim = new RectFSpringAnim(useTaskbarHotseatParams 365 ? new TaskbarHotseatSpringConfig(mContext, startRect, targetRect) 366 : new DefaultSpringConfig(mContext, mDp, startRect, targetRect)); 367 homeAnimationFactory.setAnimation(anim); 368 369 SpringAnimationRunner runner = new SpringAnimationRunner( 370 homeAnimationFactory, 371 cropRectF, 372 homeToWindowPositionMap, 373 transformParams, 374 taskViewSimulator, 375 invariantStartRect); 376 anim.addAnimatorListener(runner); 377 anim.addOnUpdateListener(runner); 378 return anim; 379 } 380 381 protected class SpringAnimationRunner extends AnimationSuccessListener 382 implements RectFSpringAnim.OnUpdateListener, BuilderProxy { 383 384 final Rect mCropRect = new Rect(); 385 final Matrix mMatrix = new Matrix(); 386 387 final RectF mWindowCurrentRect = new RectF(); 388 final Matrix mHomeToWindowPositionMap; 389 private final TransformParams mLocalTransformParams; 390 final HomeAnimationFactory mAnimationFactory; 391 392 final AnimatorPlaybackController mHomeAnim; 393 final RectF mCropRectF; 394 395 final float mStartRadius; 396 final float mEndRadius; 397 398 final RectF mRunningTaskViewStartRectF; 399 @Nullable 400 final TaskView mTargetTaskView; 401 final float mRunningTaskViewScrollOffset; 402 final float mTaskViewWidth; 403 final float mTaskViewHeight; 404 final boolean mIsPortrait; 405 final Rect mThumbnailStartBounds = new Rect(); 406 407 // Store the mTargetTaskView view properties onAnimationStart so that we can reset them 408 // when cleaning up. 409 float mTaskViewAlpha; 410 float mTaskViewTranslationX; 411 float mTaskViewTranslationY; 412 float mTaskViewScaleX; 413 float mTaskViewScaleY; 414 SpringAnimationRunner( HomeAnimationFactory factory, RectF cropRectF, Matrix homeToWindowPositionMap, TransformParams transformParams, TaskViewSimulator taskViewSimulator, RectF invariantStartRect)415 SpringAnimationRunner( 416 HomeAnimationFactory factory, 417 RectF cropRectF, 418 Matrix homeToWindowPositionMap, 419 TransformParams transformParams, 420 TaskViewSimulator taskViewSimulator, 421 RectF invariantStartRect) { 422 mAnimationFactory = factory; 423 mHomeAnim = factory.createActivityAnimationToHome(); 424 mCropRectF = cropRectF; 425 mHomeToWindowPositionMap = homeToWindowPositionMap; 426 mLocalTransformParams = transformParams; 427 428 cropRectF.roundOut(mCropRect); 429 430 // End on a "round-enough" radius so that the shape reveal doesn't have to do too much 431 // rounding at the end of the animation. 432 mStartRadius = taskViewSimulator.getCurrentCornerRadius(); 433 mEndRadius = factory.getEndRadius(cropRectF); 434 435 mRunningTaskViewStartRectF = invariantStartRect; 436 mTargetTaskView = factory.getTargetTaskView(); 437 mTaskViewWidth = mTargetTaskView == null ? 0 : mTargetTaskView.getWidth(); 438 mTaskViewHeight = mTargetTaskView == null ? 0 : mTargetTaskView.getHeight(); 439 mIsPortrait = factory.isPortrait(); 440 // Use the running task's start position to determine how much it needs to be offset 441 // to end up offscreen. 442 mRunningTaskViewScrollOffset = factory.isRtl() 443 ? (Math.min(0, -invariantStartRect.right)) 444 : (Math.max(0, mDp.widthPx - invariantStartRect.left)); 445 } 446 447 @Override onUpdate(RectF currentRect, float progress)448 public void onUpdate(RectF currentRect, float progress) { 449 float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius); 450 float alpha = mAnimationFactory.getWindowAlpha(progress); 451 452 mHomeAnim.setPlayFraction(progress); 453 if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) { 454 mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect); 455 mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL); 456 mLocalTransformParams 457 .setTargetAlpha(alpha) 458 .setCornerRadius(cornerRadius); 459 } else { 460 mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, mRunningTaskViewStartRectF); 461 mWindowCurrentRect.offset(mRunningTaskViewScrollOffset * progress, 0f); 462 mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL); 463 mLocalTransformParams.setCornerRadius(mStartRadius); 464 } 465 466 mLocalTransformParams.applySurfaceParams( 467 mLocalTransformParams.createSurfaceParams(this)); 468 469 mAnimationFactory.update( 470 currentRect, 471 progress, 472 mMatrix.mapRadius(cornerRadius), 473 !enableAdditionalHomeAnimations() || mTargetTaskView == null 474 ? 0 : (int) (alpha * 255)); 475 476 if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) { 477 return; 478 } 479 if (mAnimationFactory.isAnimatingIntoIcon() && mAnimationFactory.isAnimationReady()) { 480 mTargetTaskView.setAlpha(0f); 481 return; 482 } 483 mTargetTaskView.setAlpha(mAnimationFactory.isAnimatingIntoIcon() ? 1f : alpha); 484 float width = mThumbnailStartBounds.width(); 485 float height = mThumbnailStartBounds.height(); 486 float scale = Math.min(currentRect.width(), currentRect.height()) 487 / Math.min(width, height); 488 489 mTargetTaskView.setScaleX(scale); 490 mTargetTaskView.setScaleY(scale); 491 mTargetTaskView.setTranslationX( 492 currentRect.centerX() - mThumbnailStartBounds.centerX()); 493 mTargetTaskView.setTranslationY( 494 currentRect.centerY() - mThumbnailStartBounds.centerY()); 495 } 496 497 @Override onBuildTargetParams(SurfaceProperties builder, RemoteAnimationTarget app, TransformParams params)498 public void onBuildTargetParams(SurfaceProperties builder, RemoteAnimationTarget app, 499 TransformParams params) { 500 builder.setMatrix(mMatrix) 501 .setWindowCrop(mCropRect) 502 .setCornerRadius(params.getCornerRadius()); 503 } 504 505 @Override onCancel()506 public void onCancel() { 507 cleanUp(); 508 mAnimationFactory.onCancel(); 509 } 510 511 @Override onAnimationStart(Animator animation)512 public void onAnimationStart(Animator animation) { 513 setUp(); 514 mHomeAnim.dispatchOnStart(); 515 if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) { 516 return; 517 } 518 Rect thumbnailBounds = new Rect(); 519 // Use bounds relative to mTargetTaskView since it will be scaled afterwards 520 mTargetTaskView.getThumbnailBounds(thumbnailBounds); 521 mAnimationFactory.setTaskViewArtist(new ClipIconView.TaskViewArtist( 522 mTargetTaskView::draw, 523 0f, 524 -thumbnailBounds.top, 525 Math.min(mTaskViewHeight, mTaskViewWidth), 526 mIsPortrait)); 527 } 528 setUp()529 private void setUp() { 530 if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) { 531 return; 532 } 533 RecentsView recentsView = mTargetTaskView.getRecentsView(); 534 if (recentsView != null) { 535 recentsView.setOffsetMidpointIndexOverride( 536 recentsView.indexOfChild(mTargetTaskView)); 537 } 538 mTargetTaskView.getThumbnailBounds( 539 mThumbnailStartBounds, /* relativeToDragLayer= */ true); 540 mTaskViewAlpha = mTargetTaskView.getAlpha(); 541 if (mAnimationFactory.isAnimatingIntoIcon()) { 542 return; 543 } 544 mTaskViewTranslationX = mTargetTaskView.getTranslationX(); 545 mTaskViewTranslationY = mTargetTaskView.getTranslationY(); 546 mTaskViewScaleX = mTargetTaskView.getScaleX(); 547 mTaskViewScaleY = mTargetTaskView.getScaleY(); 548 } 549 cleanUp()550 private void cleanUp() { 551 if (!enableAdditionalHomeAnimations() || mTargetTaskView == null) { 552 return; 553 } 554 RecentsView recentsView = mTargetTaskView.getRecentsView(); 555 if (recentsView != null) { 556 recentsView.setOffsetMidpointIndexOverride(INVALID_PAGE); 557 } 558 mTargetTaskView.setAlpha(mTaskViewAlpha); 559 if (!mAnimationFactory.isAnimatingIntoIcon()) { 560 mTargetTaskView.setTranslationX(mTaskViewTranslationX); 561 mTargetTaskView.setTranslationY(mTaskViewTranslationY); 562 mTargetTaskView.setScaleX(mTaskViewScaleX); 563 mTargetTaskView.setScaleY(mTaskViewScaleY); 564 return; 565 } 566 mAnimationFactory.setTaskViewArtist(null); 567 } 568 569 @Override onAnimationSuccess(Animator animator)570 public void onAnimationSuccess(Animator animator) { 571 cleanUp(); 572 mHomeAnim.getAnimationPlayer().end(); 573 } 574 } 575 576 public interface RunningWindowAnim { end()577 void end(); 578 cancel()579 void cancel(); 580 wrap(Animator animator)581 static RunningWindowAnim wrap(Animator animator) { 582 return new RunningWindowAnim() { 583 @Override 584 public void end() { 585 animator.end(); 586 } 587 588 @Override 589 public void cancel() { 590 animator.cancel(); 591 } 592 }; 593 } 594 wrap(RectFSpringAnim rectFSpringAnim)595 static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) { 596 return new RunningWindowAnim() { 597 @Override 598 public void end() { 599 rectFSpringAnim.end(); 600 } 601 602 @Override 603 public void cancel() { 604 rectFSpringAnim.cancel(); 605 } 606 }; 607 } 608 } 609 } 610