• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 android.view.RemoteAnimationTarget.MODE_CLOSING;
19 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
20 
21 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
22 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
23 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION;
24 
25 import android.graphics.Rect;
26 import android.util.ArraySet;
27 import android.view.RemoteAnimationTarget;
28 
29 import androidx.annotation.BinderThread;
30 import androidx.annotation.NonNull;
31 import androidx.annotation.UiThread;
32 
33 import com.android.launcher3.Utilities;
34 import com.android.launcher3.util.Preconditions;
35 import com.android.quickstep.util.ActiveGestureErrorDetector;
36 import com.android.quickstep.util.ActiveGestureLog;
37 import com.android.systemui.shared.recents.model.ThumbnailData;
38 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
39 
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.HashMap;
43 import java.util.Set;
44 
45 /**
46  * Wrapper around {@link com.android.systemui.shared.system.RecentsAnimationListener} which
47  * delegates callbacks to multiple listeners on the main thread
48  */
49 public class RecentsAnimationCallbacks implements
50         com.android.systemui.shared.system.RecentsAnimationListener {
51 
52     private final Set<RecentsAnimationListener> mListeners = new ArraySet<>();
53     private final SystemUiProxy mSystemUiProxy;
54     private final boolean mAllowMinimizeSplitScreen;
55 
56     // TODO(141886704): Remove these references when they are no longer needed
57     private RecentsAnimationController mController;
58 
59     private boolean mCancelled;
60 
RecentsAnimationCallbacks(SystemUiProxy systemUiProxy, boolean allowMinimizeSplitScreen)61     public RecentsAnimationCallbacks(SystemUiProxy systemUiProxy,
62             boolean allowMinimizeSplitScreen) {
63         mSystemUiProxy = systemUiProxy;
64         mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
65     }
66 
67     @UiThread
addListener(RecentsAnimationListener listener)68     public void addListener(RecentsAnimationListener listener) {
69         Preconditions.assertUIThread();
70         mListeners.add(listener);
71     }
72 
73     @UiThread
removeListener(RecentsAnimationListener listener)74     public void removeListener(RecentsAnimationListener listener) {
75         Preconditions.assertUIThread();
76         mListeners.remove(listener);
77     }
78 
79     @UiThread
removeAllListeners()80     public void removeAllListeners() {
81         Preconditions.assertUIThread();
82         mListeners.clear();
83     }
84 
notifyAnimationCanceled()85     public void notifyAnimationCanceled() {
86         mCancelled = true;
87         onAnimationCanceled(new HashMap<>());
88     }
89 
90     // Called only in Q platform
91     @BinderThread
92     @Deprecated
onAnimationStart(RecentsAnimationControllerCompat controller, RemoteAnimationTarget[] appTargets, Rect homeContentInsets, Rect minimizedHomeBounds)93     public final void onAnimationStart(RecentsAnimationControllerCompat controller,
94             RemoteAnimationTarget[] appTargets, Rect homeContentInsets,
95             Rect minimizedHomeBounds) {
96         onAnimationStart(controller, appTargets, new RemoteAnimationTarget[0],
97                 homeContentInsets, minimizedHomeBounds);
98     }
99 
100     // Called only in R+ platform
101     @BinderThread
onAnimationStart(RecentsAnimationControllerCompat animationController, RemoteAnimationTarget[] appTargets, RemoteAnimationTarget[] wallpaperTargets, Rect homeContentInsets, Rect minimizedHomeBounds)102     public final void onAnimationStart(RecentsAnimationControllerCompat animationController,
103             RemoteAnimationTarget[] appTargets,
104             RemoteAnimationTarget[] wallpaperTargets,
105             Rect homeContentInsets, Rect minimizedHomeBounds) {
106         long appCount = Arrays.stream(appTargets)
107                 .filter(app -> app.mode == MODE_CLOSING)
108                 .count();
109         if (appCount == 0) {
110             // Edge case, if there are no closing app targets, then Launcher has nothing to handle
111             ActiveGestureLog.INSTANCE.addLog(
112                     /* event= */ "RecentsAnimationCallbacks.onAnimationStart (canceled)",
113                     /* extras= */ 0,
114                     /* gestureEvent= */ START_RECENTS_ANIMATION);
115             notifyAnimationCanceled();
116             animationController.finish(false /* toHome */, false /* sendUserLeaveHint */);
117             return;
118         }
119 
120         mController = new RecentsAnimationController(animationController,
121                 mAllowMinimizeSplitScreen, this::onAnimationFinished);
122         if (mCancelled) {
123             Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(),
124                     mController::finishAnimationToApp);
125         } else {
126             RemoteAnimationTarget[] nonAppTargets;
127             if (!TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
128                 nonAppTargets = mSystemUiProxy.onGoingToRecentsLegacy(appTargets);
129             } else {
130                 final ArrayList<RemoteAnimationTarget> apps = new ArrayList<>();
131                 final ArrayList<RemoteAnimationTarget> nonApps = new ArrayList<>();
132                 classifyTargets(appTargets, apps, nonApps);
133                 appTargets = apps.toArray(new RemoteAnimationTarget[apps.size()]);
134                 nonAppTargets = nonApps.toArray(new RemoteAnimationTarget[nonApps.size()]);
135             }
136             if (nonAppTargets == null) {
137                 nonAppTargets = new RemoteAnimationTarget[0];
138             }
139             final RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
140                     wallpaperTargets, nonAppTargets, homeContentInsets, minimizedHomeBounds);
141 
142             Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
143                 ActiveGestureLog.INSTANCE.addLog(
144                         /* event= */ "RecentsAnimationCallbacks.onAnimationStart",
145                         /* extras= */ targets.apps.length,
146                         /* gestureEvent= */ START_RECENTS_ANIMATION);
147                 for (RecentsAnimationListener listener : getListeners()) {
148                     listener.onRecentsAnimationStart(mController, targets);
149                 }
150             });
151         }
152     }
153 
154     @BinderThread
155     @Override
onAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas)156     public final void onAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
157         Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
158             ActiveGestureLog.INSTANCE.addLog(
159                     /* event= */ "RecentsAnimationCallbacks.onAnimationCanceled",
160                     /* gestureEvent= */ CANCEL_RECENTS_ANIMATION);
161             for (RecentsAnimationListener listener : getListeners()) {
162                 listener.onRecentsAnimationCanceled(thumbnailDatas);
163             }
164         });
165     }
166 
167     @BinderThread
168     @Override
onTasksAppeared(RemoteAnimationTarget[] apps)169     public void onTasksAppeared(RemoteAnimationTarget[] apps) {
170         Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
171             ActiveGestureLog.INSTANCE.addLog("RecentsAnimationCallbacks.onTasksAppeared",
172                     ActiveGestureErrorDetector.GestureEvent.TASK_APPEARED);
173             for (RecentsAnimationListener listener : getListeners()) {
174                 listener.onTasksAppeared(apps);
175             }
176         });
177     }
178 
179     @BinderThread
180     @Override
onSwitchToScreenshot(Runnable onFinished)181     public boolean onSwitchToScreenshot(Runnable onFinished) {
182         Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
183             for (RecentsAnimationListener listener : getListeners()) {
184                 if (listener.onSwitchToScreenshot(onFinished)) return;
185             }
186             onFinished.run();
187         });
188         return true;
189     }
190 
onAnimationFinished(RecentsAnimationController controller)191     private final void onAnimationFinished(RecentsAnimationController controller) {
192         Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
193             ActiveGestureLog.INSTANCE.addLog(
194                     /* event= */ "RecentsAnimationCallbacks.onAnimationFinished");
195             for (RecentsAnimationListener listener : getListeners()) {
196                 listener.onRecentsAnimationFinished(controller);
197             }
198         });
199     }
200 
getListeners()201     private RecentsAnimationListener[] getListeners() {
202         return mListeners.toArray(new RecentsAnimationListener[mListeners.size()]);
203     }
204 
classifyTargets(RemoteAnimationTarget[] appTargets, ArrayList<RemoteAnimationTarget> apps, ArrayList<RemoteAnimationTarget> nonApps)205     private void classifyTargets(RemoteAnimationTarget[] appTargets,
206             ArrayList<RemoteAnimationTarget> apps, ArrayList<RemoteAnimationTarget> nonApps) {
207         for (int i = 0; i < appTargets.length; i++) {
208             RemoteAnimationTarget target = appTargets[i];
209             if (target.windowType == TYPE_DOCK_DIVIDER) {
210                 nonApps.add(target);
211             } else {
212                 apps.add(target);
213             }
214         }
215     }
216 
217     /**
218      * Listener for the recents animation callbacks.
219      */
220     public interface RecentsAnimationListener {
onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets)221         default void onRecentsAnimationStart(RecentsAnimationController controller,
222                 RecentsAnimationTargets targets) {}
223 
224         /**
225          * Callback from the system when the recents animation is canceled. {@param thumbnailData}
226          * is passed back for rendering screenshot to replace live tile.
227          */
onRecentsAnimationCanceled( @onNull HashMap<Integer, ThumbnailData> thumbnailDatas)228         default void onRecentsAnimationCanceled(
229                 @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {}
230 
231         /**
232          * Callback made whenever the recents animation is finished.
233          */
onRecentsAnimationFinished(@onNull RecentsAnimationController controller)234         default void onRecentsAnimationFinished(@NonNull RecentsAnimationController controller) {}
235 
236         /**
237          * Callback made when a task started from the recents is ready for an app transition.
238          */
onTasksAppeared(@onNull RemoteAnimationTarget[] appearedTaskTarget)239         default void onTasksAppeared(@NonNull RemoteAnimationTarget[] appearedTaskTarget) {}
240 
241         /**
242          * @return whether this will call onFinished or not (onFinished should only be called once).
243          */
onSwitchToScreenshot(Runnable onFinished)244         default boolean onSwitchToScreenshot(Runnable onFinished) {
245             return false;
246         }
247     }
248 }
249