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