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 
17 package android.window;
18 
19 import android.annotation.BinderThread;
20 import android.annotation.CallSuper;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SuppressLint;
25 import android.annotation.TestApi;
26 import android.app.ActivityManager;
27 import android.os.IBinder;
28 import android.os.RemoteException;
29 import android.view.SurfaceControl;
30 
31 import com.android.internal.annotations.VisibleForTesting;
32 
33 import java.util.List;
34 import java.util.concurrent.Executor;
35 
36 /**
37  * Interface for ActivityTaskManager/WindowManager to delegate control of tasks.
38  * @hide
39  */
40 @TestApi
41 public class TaskOrganizer extends WindowOrganizer {
42 
43     private final ITaskOrganizerController mTaskOrganizerController;
44     // Callbacks WM Core are posted on this executor if it isn't null, otherwise direct calls are
45     // made on the incoming binder call.
46     private final Executor mExecutor;
47 
TaskOrganizer()48     public TaskOrganizer() {
49         this(null /*taskOrganizerController*/, null /*executor*/);
50     }
51 
52     /** @hide */
53     @VisibleForTesting
TaskOrganizer(ITaskOrganizerController taskOrganizerController, Executor executor)54     public TaskOrganizer(ITaskOrganizerController taskOrganizerController, Executor executor) {
55         mExecutor = executor != null ? executor : Runnable::run;
56         mTaskOrganizerController = taskOrganizerController != null
57                 ? taskOrganizerController : getController();
58     }
59 
60     /**
61      * Register a TaskOrganizer to manage tasks as they enter a supported windowing mode.
62      *
63      * @return a list of the tasks that should be managed by the organizer, not including tasks
64      *         created via {@link #createRootTask}.
65      */
66     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
67     @CallSuper
68     @NonNull
registerOrganizer()69     public List<TaskAppearedInfo> registerOrganizer() {
70         try {
71             return mTaskOrganizerController.registerTaskOrganizer(mInterface).getList();
72         } catch (RemoteException e) {
73             throw e.rethrowFromSystemServer();
74         }
75     }
76 
77     /** Unregisters a previously registered task organizer. */
78     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
79     @CallSuper
unregisterOrganizer()80     public void unregisterOrganizer() {
81         try {
82             mTaskOrganizerController.unregisterTaskOrganizer(mInterface);
83         } catch (RemoteException e) {
84             throw e.rethrowFromSystemServer();
85         }
86     }
87 
88     /**
89      * Called when a Task is starting and the system would like to show a UI to indicate that an
90      * application is starting. The client is responsible to add/remove the starting window if it
91      * has create a starting window for the Task.
92      *
93      * @param info The information about the Task that's available
94      * @param appToken Token of the application being started.
95      *        context to for resources
96      * @hide
97      */
98     @BinderThread
addStartingWindow(@onNull StartingWindowInfo info, @NonNull IBinder appToken)99     public void addStartingWindow(@NonNull StartingWindowInfo info,
100             @NonNull IBinder appToken) {}
101 
102     /**
103      * Called when the Task want to remove the starting window.
104      * @param removalInfo The information used to remove the starting window.
105      * @hide
106      */
107     @BinderThread
removeStartingWindow(@onNull StartingWindowRemovalInfo removalInfo)108     public void removeStartingWindow(@NonNull StartingWindowRemovalInfo removalInfo) {}
109 
110     /**
111      * Called when the Task want to copy the splash screen.
112      */
113     @BinderThread
copySplashScreenView(int taskId)114     public void copySplashScreenView(int taskId) {}
115 
116     /**
117      * Notify the shell ({@link com.android.wm.shell.ShellTaskOrganizer} that the client has
118      * removed the splash screen view.
119      * @see com.android.wm.shell.ShellTaskOrganizer#onAppSplashScreenViewRemoved(int)
120      * @see SplashScreenView#remove()
121      */
122     @BinderThread
onAppSplashScreenViewRemoved(int taskId)123     public void onAppSplashScreenViewRemoved(int taskId) {
124     }
125 
126     /**
127      * Called when a task with the registered windowing mode can be controlled by this task
128      * organizer. For non-root tasks, the leash may initially be hidden so it is up to the organizer
129      * to show this task.
130      */
131     @BinderThread
onTaskAppeared(@onNull ActivityManager.RunningTaskInfo taskInfo, @NonNull SurfaceControl leash)132     public void onTaskAppeared(@NonNull ActivityManager.RunningTaskInfo taskInfo,
133             @NonNull SurfaceControl leash) {}
134 
135     @BinderThread
onTaskVanished(@onNull ActivityManager.RunningTaskInfo taskInfo)136     public void onTaskVanished(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
137 
138     @BinderThread
onTaskInfoChanged(@onNull ActivityManager.RunningTaskInfo taskInfo)139     public void onTaskInfoChanged(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
140 
141     @BinderThread
onBackPressedOnTaskRoot(@onNull ActivityManager.RunningTaskInfo taskInfo)142     public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
143 
144     /** @hide */
145     @BinderThread
onImeDrawnOnTask(int taskId)146     public void onImeDrawnOnTask(int taskId) {}
147 
148     /**
149      * Creates a persistent root task in WM for a particular windowing-mode.
150      * @param displayId The display to create the root task on.
151      * @param windowingMode Windowing mode to put the root task in.
152      * @param launchCookie Launch cookie to associate with the task so that is can be identified
153      *                     when the {@link ITaskOrganizer#onTaskAppeared} callback is called.
154      */
155     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
156     @Nullable
createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie)157     public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) {
158         try {
159             mTaskOrganizerController.createRootTask(displayId, windowingMode, launchCookie);
160         } catch (RemoteException e) {
161             throw e.rethrowFromSystemServer();
162         }
163     }
164 
165     /** Deletes a persistent root task in WM */
166     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
deleteRootTask(@onNull WindowContainerToken task)167     public boolean deleteRootTask(@NonNull WindowContainerToken task) {
168         try {
169             return mTaskOrganizerController.deleteRootTask(task);
170         } catch (RemoteException e) {
171             throw e.rethrowFromSystemServer();
172         }
173     }
174 
175     /** Gets direct child tasks (ordered from top-to-bottom) */
176     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
177     @Nullable
178     @SuppressLint("NullableCollection")
getChildTasks( @onNull WindowContainerToken parent, @NonNull int[] activityTypes)179     public List<ActivityManager.RunningTaskInfo> getChildTasks(
180             @NonNull WindowContainerToken parent, @NonNull int[] activityTypes) {
181         try {
182             return mTaskOrganizerController.getChildTasks(parent, activityTypes);
183         } catch (RemoteException e) {
184             throw e.rethrowFromSystemServer();
185         }
186     }
187 
188     /** Gets all root tasks on a display (ordered from top-to-bottom) */
189     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
190     @Nullable
191     @SuppressLint("NullableCollection")
getRootTasks( int displayId, @NonNull int[] activityTypes)192     public List<ActivityManager.RunningTaskInfo> getRootTasks(
193             int displayId, @NonNull int[] activityTypes) {
194         try {
195             return mTaskOrganizerController.getRootTasks(displayId, activityTypes);
196         } catch (RemoteException e) {
197             throw e.rethrowFromSystemServer();
198         }
199     }
200 
201     /** Get the root task which contains the current ime target */
202     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
203     @Nullable
getImeTarget(int display)204     public WindowContainerToken getImeTarget(int display) {
205         try {
206             return mTaskOrganizerController.getImeTarget(display);
207         } catch (RemoteException e) {
208             throw e.rethrowFromSystemServer();
209         }
210     }
211 
212     /**
213      * Requests that the given task organizer is notified when back is pressed on the root activity
214      * of one of its controlled tasks.
215      */
216     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
setInterceptBackPressedOnTaskRoot(@onNull WindowContainerToken task, boolean interceptBackPressed)217     public void setInterceptBackPressedOnTaskRoot(@NonNull WindowContainerToken task,
218             boolean interceptBackPressed) {
219         try {
220             mTaskOrganizerController.setInterceptBackPressedOnTaskRoot(task, interceptBackPressed);
221         } catch (RemoteException e) {
222             throw e.rethrowFromSystemServer();
223         }
224     }
225 
226 
227     /**
228      * Restarts the top activity in the given task by killing its process if it is visible.
229      * @hide
230      */
231     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
restartTaskTopActivityProcessIfVisible(@onNull WindowContainerToken task)232     public void restartTaskTopActivityProcessIfVisible(@NonNull WindowContainerToken task) {
233         try {
234             mTaskOrganizerController.restartTaskTopActivityProcessIfVisible(task);
235         } catch (RemoteException e) {
236             throw e.rethrowFromSystemServer();
237         }
238     }
239 
240     /**
241      * Gets the executor to run callbacks on.
242      * @hide
243      */
244     @NonNull
getExecutor()245     public Executor getExecutor() {
246         return mExecutor;
247     }
248 
249     private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
250         @Override
251         public void addStartingWindow(StartingWindowInfo windowInfo,
252                 IBinder appToken) {
253             mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken));
254         }
255 
256         @Override
257         public void removeStartingWindow(StartingWindowRemovalInfo removalInfo) {
258             mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(removalInfo));
259         }
260 
261         @Override
262         public void copySplashScreenView(int taskId)  {
263             mExecutor.execute(() -> TaskOrganizer.this.copySplashScreenView(taskId));
264         }
265 
266         @Override
267         public void onAppSplashScreenViewRemoved(int taskId) {
268             mExecutor.execute(() -> TaskOrganizer.this.onAppSplashScreenViewRemoved(taskId));
269         }
270 
271         @Override
272         public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
273             mExecutor.execute(() -> TaskOrganizer.this.onTaskAppeared(taskInfo, leash));
274         }
275 
276         @Override
277         public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
278             mExecutor.execute(() -> TaskOrganizer.this.onTaskVanished(taskInfo));
279         }
280 
281         @Override
282         public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
283             mExecutor.execute(() -> TaskOrganizer.this.onTaskInfoChanged(info));
284         }
285 
286         @Override
287         public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo info) {
288             mExecutor.execute(() -> TaskOrganizer.this.onBackPressedOnTaskRoot(info));
289         }
290 
291         @Override
292         public void onImeDrawnOnTask(int taskId) {
293             mExecutor.execute(() -> TaskOrganizer.this.onImeDrawnOnTask(taskId));
294         }
295     };
296 
297     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
getController()298     private ITaskOrganizerController getController() {
299         try {
300             return getWindowOrganizerController().getTaskOrganizerController();
301         } catch (RemoteException e) {
302             return null;
303         }
304     }
305 }
306