1 /* 2 * Copyright (C) 2018 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 17 package com.android.launcher3; 18 19 import static com.android.launcher3.LauncherState.NORMAL; 20 import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE; 21 import static com.android.launcher3.anim.Interpolators.LINEAR; 22 import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator; 23 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch; 24 25 import android.animation.Animator; 26 import android.animation.AnimatorListenerAdapter; 27 import android.animation.AnimatorSet; 28 import android.animation.ObjectAnimator; 29 import android.content.Context; 30 import android.view.View; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.Nullable; 34 35 import com.android.launcher3.anim.AnimatorPlaybackController; 36 import com.android.launcher3.anim.Interpolators; 37 import com.android.launcher3.anim.PendingAnimation; 38 import com.android.quickstep.views.RecentsView; 39 import com.android.quickstep.views.TaskView; 40 import com.android.systemui.shared.system.RemoteAnimationTargetCompat; 41 42 /** 43 * A {@link QuickstepAppTransitionManagerImpl} that also implements recents transitions from 44 * {@link RecentsView}. 45 */ 46 public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransitionManagerImpl { 47 LauncherAppTransitionManagerImpl(Context context)48 public LauncherAppTransitionManagerImpl(Context context) { 49 super(context); 50 } 51 52 @Override isLaunchingFromRecents(@onNull View v, @Nullable RemoteAnimationTargetCompat[] targets)53 protected boolean isLaunchingFromRecents(@NonNull View v, 54 @Nullable RemoteAnimationTargetCompat[] targets) { 55 return mLauncher.getStateManager().getState().overviewUi 56 && findTaskViewToLaunch(mLauncher, v, targets) != null; 57 } 58 59 @Override composeRecentsLaunchAnimator(@onNull AnimatorSet anim, @NonNull View v, @NonNull RemoteAnimationTargetCompat[] appTargets, @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing)60 protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v, 61 @NonNull RemoteAnimationTargetCompat[] appTargets, 62 @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) { 63 RecentsView recentsView = mLauncher.getOverviewPanel(); 64 boolean skipLauncherChanges = !launcherClosing; 65 66 TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets); 67 PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION); 68 createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets, 69 mLauncher.getDepthController(), pa); 70 anim.play(pa.buildAnim()); 71 72 Animator childStateAnimation = null; 73 // Found a visible recents task that matches the opening app, lets launch the app from there 74 Animator launcherAnim; 75 final AnimatorListenerAdapter windowAnimEndListener; 76 if (launcherClosing) { 77 launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView); 78 launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); 79 launcherAnim.setDuration(RECENTS_LAUNCH_DURATION); 80 81 // Make sure recents gets fixed up by resetting task alphas and scales, etc. 82 windowAnimEndListener = new AnimatorListenerAdapter() { 83 @Override 84 public void onAnimationEnd(Animator animation) { 85 mLauncher.getStateManager().moveToRestState(); 86 mLauncher.getStateManager().reapplyState(); 87 } 88 }; 89 } else { 90 AnimatorPlaybackController controller = 91 mLauncher.getStateManager().createAnimationToNewWorkspace(NORMAL, 92 RECENTS_LAUNCH_DURATION); 93 controller.dispatchOnStart(); 94 childStateAnimation = controller.getTarget(); 95 launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION); 96 windowAnimEndListener = new AnimatorListenerAdapter() { 97 @Override 98 public void onAnimationEnd(Animator animation) { 99 mLauncher.getStateManager().goToState(NORMAL, false); 100 } 101 }; 102 } 103 anim.play(launcherAnim); 104 105 // Set the current animation first, before adding windowAnimEndListener. Setting current 106 // animation adds some listeners which need to be called before windowAnimEndListener 107 // (the ordering of listeners matter in this case). 108 mLauncher.getStateManager().setCurrentAnimation(anim, childStateAnimation); 109 anim.addListener(windowAnimEndListener); 110 } 111 112 @Override composeViewContentAnimator(@onNull AnimatorSet anim, float[] alphas, float[] trans)113 protected Runnable composeViewContentAnimator(@NonNull AnimatorSet anim, float[] alphas, 114 float[] trans) { 115 RecentsView overview = mLauncher.getOverviewPanel(); 116 ObjectAnimator alpha = ObjectAnimator.ofFloat(overview, 117 RecentsView.CONTENT_ALPHA, alphas); 118 alpha.setDuration(CONTENT_ALPHA_DURATION); 119 alpha.setInterpolator(LINEAR); 120 anim.play(alpha); 121 overview.setFreezeViewVisibility(true); 122 123 ObjectAnimator transY = ObjectAnimator.ofFloat(overview, View.TRANSLATION_Y, trans); 124 transY.setInterpolator(AGGRESSIVE_EASE); 125 transY.setDuration(CONTENT_TRANSLATION_DURATION); 126 anim.play(transY); 127 128 return () -> { 129 overview.setFreezeViewVisibility(false); 130 overview.setTranslationY(0); 131 mLauncher.getStateManager().reapplyState(); 132 }; 133 } 134 } 135