• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.quickstep;
17 
18 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
19 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
20 
21 import android.view.IRecentsAnimationController;
22 import android.view.SurfaceControl;
23 import android.window.PictureInPictureSurfaceTransaction;
24 
25 import androidx.annotation.NonNull;
26 import androidx.annotation.UiThread;
27 
28 import com.android.launcher3.util.Preconditions;
29 import com.android.launcher3.util.RunnableList;
30 import com.android.systemui.shared.recents.model.ThumbnailData;
31 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
32 import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
33 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
34 
35 import java.util.function.Consumer;
36 
37 /**
38  * Wrapper around RecentsAnimationControllerCompat to help with some synchronization
39  */
40 public class RecentsAnimationController {
41 
42     private final RecentsAnimationControllerCompat mController;
43     private final Consumer<RecentsAnimationController> mOnFinishedListener;
44     private final boolean mAllowMinimizeSplitScreen;
45 
46     private boolean mUseLauncherSysBarFlags = false;
47     private boolean mSplitScreenMinimized = false;
48     private boolean mFinishRequested = false;
49     private RunnableList mPendingFinishCallbacks = new RunnableList();
50 
RecentsAnimationController(RecentsAnimationControllerCompat controller, boolean allowMinimizeSplitScreen, Consumer<RecentsAnimationController> onFinishedListener)51     public RecentsAnimationController(RecentsAnimationControllerCompat controller,
52             boolean allowMinimizeSplitScreen,
53             Consumer<RecentsAnimationController> onFinishedListener) {
54         mController = controller;
55         mOnFinishedListener = onFinishedListener;
56         mAllowMinimizeSplitScreen = allowMinimizeSplitScreen;
57     }
58 
59     /**
60      * Synchronously takes a screenshot of the task with the given {@param taskId} if the task is
61      * currently being animated.
62      */
screenshotTask(int taskId)63     public ThumbnailData screenshotTask(int taskId) {
64         return mController.screenshotTask(taskId);
65     }
66 
67     /**
68      * Indicates that the gesture has crossed the window boundary threshold and system UI can be
69      * update the system bar flags accordingly.
70      */
setUseLauncherSystemBarFlags(boolean useLauncherSysBarFlags)71     public void setUseLauncherSystemBarFlags(boolean useLauncherSysBarFlags) {
72         if (mUseLauncherSysBarFlags != useLauncherSysBarFlags) {
73             mUseLauncherSysBarFlags = useLauncherSysBarFlags;
74             UI_HELPER_EXECUTOR.execute(() -> {
75                 mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
76             });
77         }
78     }
79 
80     /**
81      * Indicates that the gesture has crossed the window boundary threshold and we should minimize
82      * if we are in splitscreen.
83      */
setSplitScreenMinimized(boolean splitScreenMinimized)84     public void setSplitScreenMinimized(boolean splitScreenMinimized) {
85         if (!mAllowMinimizeSplitScreen) {
86             return;
87         }
88         if (mSplitScreenMinimized != splitScreenMinimized) {
89             mSplitScreenMinimized = splitScreenMinimized;
90             UI_HELPER_EXECUTOR.execute(() -> {
91                 SystemUiProxy p = SystemUiProxy.INSTANCE.getNoCreate();
92                 if (p != null) {
93                     p.setSplitScreenMinimized(splitScreenMinimized);
94                 }
95             });
96         }
97     }
98 
99     /**
100      * Remove task remote animation target from
101      * {@link RecentsAnimationCallbacks#onTaskAppeared(RemoteAnimationTargetCompat)}}.
102      */
103     @UiThread
removeTaskTarget(@onNull RemoteAnimationTargetCompat target)104     public void removeTaskTarget(@NonNull RemoteAnimationTargetCompat target) {
105         UI_HELPER_EXECUTOR.execute(() -> mController.removeTask(target.taskId));
106     }
107 
108     @UiThread
finishAnimationToHome()109     public void finishAnimationToHome() {
110         finishController(true /* toRecents */, null, false /* sendUserLeaveHint */);
111     }
112 
113     @UiThread
finishAnimationToApp()114     public void finishAnimationToApp() {
115         finishController(false /* toRecents */, null, false /* sendUserLeaveHint */);
116     }
117 
118     /** See {@link #finish(boolean, Runnable, boolean)} */
119     @UiThread
finish(boolean toRecents, Runnable onFinishComplete)120     public void finish(boolean toRecents, Runnable onFinishComplete) {
121         finish(toRecents, onFinishComplete, false /* sendUserLeaveHint */);
122     }
123 
124     /**
125      * @param onFinishComplete A callback that runs on the main thread after the animation
126      *                         controller has finished on the background thread.
127      * @param sendUserLeaveHint Determines whether userLeaveHint flag will be set on the pausing
128      *                          activity. If userLeaveHint is true, the activity will enter into
129      *                          picture-in-picture mode upon being paused.
130      */
131     @UiThread
finish(boolean toRecents, Runnable onFinishComplete, boolean sendUserLeaveHint)132     public void finish(boolean toRecents, Runnable onFinishComplete, boolean sendUserLeaveHint) {
133         Preconditions.assertUIThread();
134         finishController(toRecents, onFinishComplete, sendUserLeaveHint);
135     }
136 
137     @UiThread
finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint)138     public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) {
139         if (mFinishRequested) {
140             // If finishing, add to pending finish callbacks, otherwise, if finished, adding to the
141             // destroyed RunnableList will just trigger the callback to be called immediately
142             mPendingFinishCallbacks.add(callback);
143             return;
144         }
145 
146         // Finish not yet requested
147         mFinishRequested = true;
148         mOnFinishedListener.accept(this);
149         mPendingFinishCallbacks.add(callback);
150         UI_HELPER_EXECUTOR.execute(() -> {
151             mController.finish(toRecents, sendUserLeaveHint);
152             InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
153             InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
154             MAIN_EXECUTOR.execute(mPendingFinishCallbacks::executeAllAndDestroy);
155         });
156     }
157 
158     /**
159      * @see IRecentsAnimationController#cleanupScreenshot()
160      */
161     @UiThread
cleanupScreenshot()162     public void cleanupScreenshot() {
163         UI_HELPER_EXECUTOR.execute(() -> mController.cleanupScreenshot());
164     }
165 
166     /**
167      * @see RecentsAnimationControllerCompat#detachNavigationBarFromApp
168      */
169     @UiThread
detachNavigationBarFromApp(boolean moveHomeToTop)170     public void detachNavigationBarFromApp(boolean moveHomeToTop) {
171         UI_HELPER_EXECUTOR.execute(() -> mController.detachNavigationBarFromApp(moveHomeToTop));
172     }
173 
174     /**
175      * @see IRecentsAnimationController#animateNavigationBarToApp(long)
176      */
177     @UiThread
animateNavigationBarToApp(long duration)178     public void animateNavigationBarToApp(long duration) {
179         UI_HELPER_EXECUTOR.execute(() -> mController.animateNavigationBarToApp(duration));
180     }
181 
182     /**
183      * @see IRecentsAnimationController#setWillFinishToHome(boolean)
184      */
185     @UiThread
setWillFinishToHome(boolean willFinishToHome)186     public void setWillFinishToHome(boolean willFinishToHome) {
187         UI_HELPER_EXECUTOR.execute(() -> mController.setWillFinishToHome(willFinishToHome));
188     }
189 
190     /**
191      * Sets the final surface transaction on a Task. This is used by Launcher to notify the system
192      * that animating Activity to PiP has completed and the associated task surface should be
193      * updated accordingly. This should be called before `finish`
194      * @param taskId for which the leash should be updated
195      * @param finishTransaction the transaction to transfer to the task surface control after the
196      *                          leash is removed
197      * @param overlay the surface control for an overlay being shown above the pip (can be null)
198      */
setFinishTaskTransaction(int taskId, PictureInPictureSurfaceTransaction finishTransaction, SurfaceControl overlay)199     public void setFinishTaskTransaction(int taskId,
200             PictureInPictureSurfaceTransaction finishTransaction,
201             SurfaceControl overlay) {
202         UI_HELPER_EXECUTOR.execute(
203                 () -> mController.setFinishTaskTransaction(taskId, finishTransaction, overlay));
204     }
205 
206     /**
207      * Enables the input consumer to start intercepting touches in the app window.
208      */
enableInputConsumer()209     public void enableInputConsumer() {
210         UI_HELPER_EXECUTOR.submit(() -> {
211             mController.hideCurrentInputMethod();
212             mController.setInputConsumerEnabled(true);
213         });
214     }
215 
216     /** @return wrapper controller. */
getController()217     public RecentsAnimationControllerCompat getController() {
218         return mController;
219     }
220 }
221