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 android.app;
18 
19 import android.annotation.NonNull;
20 import android.annotation.RequiresPermission;
21 import android.annotation.SystemService;
22 import android.annotation.TestApi;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.content.res.Configuration;
27 import android.content.res.Resources;
28 import android.graphics.Rect;
29 import android.os.Build;
30 import android.os.Handler;
31 import android.os.IBinder;
32 import android.os.RemoteException;
33 import android.os.ServiceManager;
34 import android.util.Singleton;
35 
36 import java.util.List;
37 
38 /**
39  * This class gives information about, and interacts with activities and their containers like task,
40  * stacks, and displays.
41  *
42  * @hide
43  */
44 @TestApi
45 @SystemService(Context.ACTIVITY_TASK_SERVICE)
46 public class ActivityTaskManager {
47 
48     /** Invalid stack ID. */
49     public static final int INVALID_STACK_ID = -1;
50 
51     /**
52      * Invalid task ID.
53      * @hide
54      */
55     public static final int INVALID_TASK_ID = -1;
56 
57     /**
58      * Parameter to {@link IActivityTaskManager#setTaskWindowingModeSplitScreenPrimary} which
59      * specifies the position of the created docked stack at the top half of the screen if
60      * in portrait mode or at the left half of the screen if in landscape mode.
61      */
62     public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0;
63 
64     /**
65      * Parameter to {@link IActivityTaskManager#setTaskWindowingModeSplitScreenPrimary} which
66      * specifies the position of the created docked stack at the bottom half of the screen if
67      * in portrait mode or at the right half of the screen if in landscape mode.
68      */
69     public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
70 
71     /**
72      * Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
73      * that the resize doesn't need to preserve the window, and can be skipped if bounds
74      * is unchanged. This mode is used by window manager in most cases.
75      * @hide
76      */
77     public static final int RESIZE_MODE_SYSTEM = 0;
78 
79     /**
80      * Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
81      * that the resize should preserve the window if possible.
82      * @hide
83      */
84     public static final int RESIZE_MODE_PRESERVE_WINDOW   = (0x1 << 0);
85 
86     /**
87      * Input parameter to {@link IActivityTaskManager#resizeTask} used when the
88      * resize is due to a drag action.
89      * @hide
90      */
91     public static final int RESIZE_MODE_USER = RESIZE_MODE_PRESERVE_WINDOW;
92 
93     /**
94      * Input parameter to {@link IActivityTaskManager#resizeTask} used by window
95      * manager during a screen rotation.
96      * @hide
97      */
98     public static final int RESIZE_MODE_SYSTEM_SCREEN_ROTATION = RESIZE_MODE_PRESERVE_WINDOW;
99 
100     /**
101      * Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
102      * that the resize should be performed even if the bounds appears unchanged.
103      * @hide
104      */
105     public static final int RESIZE_MODE_FORCED = (0x1 << 1);
106 
107     /**
108      * Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
109      * that the resize should preserve the window if possible, and should not be skipped
110      * even if the bounds is unchanged. Usually used to force a resizing when a drag action
111      * is ending.
112      * @hide
113      */
114     public static final int RESIZE_MODE_USER_FORCED =
115             RESIZE_MODE_PRESERVE_WINDOW | RESIZE_MODE_FORCED;
116 
117     /**
118      * Extra included on intents that are delegating the call to
119      * ActivityManager#startActivityAsCaller to another app.  This token is necessary for that call
120      * to succeed.  Type is IBinder.
121      * @hide
122      */
123     public static final String EXTRA_PERMISSION_TOKEN = "android.app.extra.PERMISSION_TOKEN";
124 
125     /**
126      * Extra included on intents that contain an EXTRA_INTENT, with options that the contained
127      * intent may want to be started with.  Type is Bundle.
128      * TODO: remove once the ChooserActivity moves to systemui
129      * @hide
130      */
131     public static final String EXTRA_OPTIONS = "android.app.extra.OPTIONS";
132 
133     /**
134      * Extra included on intents that contain an EXTRA_INTENT, use this boolean value for the
135      * parameter of the same name when starting the contained intent.
136      * TODO: remove once the ChooserActivity moves to systemui
137      * @hide
138      */
139     public static final String EXTRA_IGNORE_TARGET_SECURITY =
140             "android.app.extra.EXTRA_IGNORE_TARGET_SECURITY";
141 
142 
143     private static int sMaxRecentTasks = -1;
144 
ActivityTaskManager(Context context, Handler handler)145     ActivityTaskManager(Context context, Handler handler) {
146     }
147 
148     /** @hide */
getService()149     public static IActivityTaskManager getService() {
150         return IActivityTaskManagerSingleton.get();
151     }
152 
153     @UnsupportedAppUsage(trackingBug = 129726065)
154     private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
155             new Singleton<IActivityTaskManager>() {
156                 @Override
157                 protected IActivityTaskManager create() {
158                     final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
159                     return IActivityTaskManager.Stub.asInterface(b);
160                 }
161             };
162 
163     /**
164      * Sets the windowing mode for a specific task. Only works on tasks of type
165      * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}
166      * @param taskId The id of the task to set the windowing mode for.
167      * @param windowingMode The windowing mode to set for the task.
168      * @param toTop If the task should be moved to the top once the windowing mode changes.
169      * @return Whether the task was successfully put into the specified windowing mode.
170      */
171     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
setTaskWindowingMode(int taskId, int windowingMode, boolean toTop)172     public boolean setTaskWindowingMode(int taskId, int windowingMode, boolean toTop)
173             throws SecurityException {
174         try {
175             return getService().setTaskWindowingMode(taskId, windowingMode, toTop);
176         } catch (RemoteException e) {
177             throw e.rethrowFromSystemServer();
178         }
179     }
180 
181     /**
182      * Moves the input task to the primary-split-screen stack.
183      * @param taskId Id of task to move.
184      * @param createMode The mode the primary split screen stack should be created in if it doesn't
185      *                   exist already. See
186      *                   {@link ActivityTaskManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
187      *                   and
188      *                   {@link android.app.ActivityManager
189      *                        #SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
190      * @param toTop If the task and stack should be moved to the top.
191      * @param animate Whether we should play an animation for the moving the task
192      * @param initialBounds If the primary stack gets created, it will use these bounds for the
193      *                      docked stack. Pass {@code null} to use default bounds.
194      * @param showRecents If the recents activity should be shown on the other side of the task
195      *                    going into split-screen mode.
196      * @return Whether the task was successfully put into splitscreen.
197      */
198     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop, boolean animate, Rect initialBounds, boolean showRecents)199     public boolean setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
200             boolean animate, Rect initialBounds, boolean showRecents) throws SecurityException {
201         try {
202             return getService().setTaskWindowingModeSplitScreenPrimary(taskId, toTop);
203         } catch (RemoteException e) {
204             throw e.rethrowFromSystemServer();
205         }
206     }
207 
208     /**
209      * Removes stacks in the windowing modes from the system if they are of activity type
210      * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
211      */
212     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
removeStacksInWindowingModes(int[] windowingModes)213     public void removeStacksInWindowingModes(int[] windowingModes) throws SecurityException {
214         try {
215             getService().removeStacksInWindowingModes(windowingModes);
216         } catch (RemoteException e) {
217             throw e.rethrowFromSystemServer();
218         }
219     }
220 
221     /** Removes stack of the activity types from the system. */
222     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
removeStacksWithActivityTypes(int[] activityTypes)223     public void removeStacksWithActivityTypes(int[] activityTypes) throws SecurityException {
224         try {
225             getService().removeStacksWithActivityTypes(activityTypes);
226         } catch (RemoteException e) {
227             throw e.rethrowFromSystemServer();
228         }
229     }
230 
231     /**
232      * Removes all visible recent tasks from the system.
233      * @hide
234      */
235     @RequiresPermission(android.Manifest.permission.REMOVE_TASKS)
removeAllVisibleRecentTasks()236     public void removeAllVisibleRecentTasks() {
237         try {
238             getService().removeAllVisibleRecentTasks();
239         } catch (RemoteException e) {
240             throw e.rethrowFromSystemServer();
241         }
242     }
243 
244     /**
245      * Return the maximum number of recents entries that we will maintain and show.
246      * @hide
247      */
getMaxRecentTasksStatic()248     public static int getMaxRecentTasksStatic() {
249         if (sMaxRecentTasks < 0) {
250             return sMaxRecentTasks = ActivityManager.isLowRamDeviceStatic() ? 36 : 48;
251         }
252         return sMaxRecentTasks;
253     }
254 
255     /**
256      * Return the default limit on the number of recents that an app can make.
257      * @hide
258      */
getDefaultAppRecentsLimitStatic()259     public static int getDefaultAppRecentsLimitStatic() {
260         return getMaxRecentTasksStatic() / 6;
261     }
262 
263     /**
264      * Return the maximum limit on the number of recents that an app can make.
265      * @hide
266      */
getMaxAppRecentsLimitStatic()267     public static int getMaxAppRecentsLimitStatic() {
268         return getMaxRecentTasksStatic() / 2;
269     }
270 
271     /**
272      * Returns true if the system supports at least one form of multi-window.
273      * E.g. freeform, split-screen, picture-in-picture.
274      */
supportsMultiWindow(Context context)275     public static boolean supportsMultiWindow(Context context) {
276         // On watches, multi-window is used to present essential system UI, and thus it must be
277         // supported regardless of device memory characteristics.
278         boolean isWatch = context.getPackageManager().hasSystemFeature(
279                 PackageManager.FEATURE_WATCH);
280         return (!ActivityManager.isLowRamDeviceStatic() || isWatch)
281                 && Resources.getSystem().getBoolean(
282                 com.android.internal.R.bool.config_supportsMultiWindow);
283     }
284 
285     /** Returns true if the system supports split screen multi-window. */
supportsSplitScreenMultiWindow(Context context)286     public static boolean supportsSplitScreenMultiWindow(Context context) {
287         return supportsMultiWindow(context)
288                 && Resources.getSystem().getBoolean(
289                 com.android.internal.R.bool.config_supportsSplitScreenMultiWindow);
290     }
291 
292     /**
293      * Moves the top activity in the input stackId to the pinned stack.
294      * @param stackId Id of stack to move the top activity to pinned stack.
295      * @param bounds Bounds to use for pinned stack.
296      * @return True if the top activity of stack was successfully moved to the pinned stack.
297      */
298     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
moveTopActivityToPinnedStack(int stackId, Rect bounds)299     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
300         try {
301             return getService().moveTopActivityToPinnedStack(stackId, bounds);
302         } catch (RemoteException e) {
303             throw e.rethrowFromSystemServer();
304         }
305     }
306 
307     /**
308      * Start to enter lock task mode for given task by system(UI).
309      * @param taskId Id of task to lock.
310      */
311     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
startSystemLockTaskMode(int taskId)312     public void startSystemLockTaskMode(int taskId) {
313         try {
314             getService().startSystemLockTaskMode(taskId);
315         } catch (RemoteException e) {
316             throw e.rethrowFromSystemServer();
317         }
318     }
319 
320     /**
321      * Stop lock task mode by system(UI).
322      */
323     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
stopSystemLockTaskMode()324     public void stopSystemLockTaskMode() {
325         try {
326             getService().stopSystemLockTaskMode();
327         } catch (RemoteException e) {
328             throw e.rethrowFromSystemServer();
329         }
330     }
331 
332     /**
333      * Move task to stack with given id.
334      * @param taskId Id of the task to move.
335      * @param stackId Id of the stack for task moving.
336      * @param toTop Whether the given task should shown to top of stack.
337      */
338     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
moveTaskToStack(int taskId, int stackId, boolean toTop)339     public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
340         try {
341             getService().moveTaskToStack(taskId, stackId, toTop);
342         } catch (RemoteException e) {
343             throw e.rethrowFromSystemServer();
344         }
345     }
346 
347     /**
348      * Resize task to given bounds.
349      * @param taskId Id of task to resize.
350      * @param bounds Bounds to resize task.
351      */
352     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
resizeTask(int taskId, Rect bounds)353     public void resizeTask(int taskId, Rect bounds) {
354         try {
355             getService().resizeTask(taskId, bounds, RESIZE_MODE_SYSTEM);
356         } catch (RemoteException e) {
357             throw e.rethrowFromSystemServer();
358         }
359     }
360 
361     /**
362      * Resize docked stack & its task to given stack & task bounds.
363      * @param stackBounds Bounds to resize stack.
364      * @param taskBounds Bounds to resize task.
365      */
366     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
resizeDockedStack(Rect stackBounds, Rect taskBounds)367     public void resizeDockedStack(Rect stackBounds, Rect taskBounds) {
368         try {
369             getService().resizeDockedStack(stackBounds, taskBounds, null, null, null);
370         } catch (RemoteException e) {
371             throw e.rethrowFromSystemServer();
372         }
373     }
374 
375     /**
376      * List all activity stacks information.
377      */
378     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
listAllStacks()379     public String listAllStacks() {
380         final List<ActivityManager.StackInfo> stacks;
381         try {
382             stacks = getService().getAllStackInfos();
383         } catch (RemoteException e) {
384             throw e.rethrowFromSystemServer();
385         }
386 
387         final StringBuilder sb = new StringBuilder();
388         if (stacks != null) {
389             for (ActivityManager.StackInfo info : stacks) {
390                 sb.append(info).append("\n");
391             }
392         }
393         return sb.toString();
394     }
395 
396     /**
397      * Clears launch params for the given package.
398      * @param packageNames the names of the packages of which the launch params are to be cleared
399      */
400     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
clearLaunchParamsForPackages(List<String> packageNames)401     public void clearLaunchParamsForPackages(List<String> packageNames) {
402         try {
403             getService().clearLaunchParamsForPackages(packageNames);
404         } catch (RemoteException e) {
405             e.rethrowFromSystemServer();
406         }
407     }
408 
409     /**
410      * Makes the display with the given id a single task instance display. I.e the display can only
411      * contain one task.
412      */
413     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
setDisplayToSingleTaskInstance(int displayId)414     public void setDisplayToSingleTaskInstance(int displayId) {
415         try {
416             getService().setDisplayToSingleTaskInstance(displayId);
417         } catch (RemoteException e) {
418             throw e.rethrowFromSystemServer();
419         }
420     }
421 
422     /**
423      * Requests that an activity should enter picture-in-picture mode if possible.
424      * @hide
425      */
426     @TestApi
427     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
requestPictureInPictureMode(@onNull IBinder token)428     public void requestPictureInPictureMode(@NonNull IBinder token) {
429         try {
430             getService().requestPictureInPictureMode(token);
431         } catch (RemoteException e) {
432             throw e.rethrowFromSystemServer();
433         }
434     }
435 
436     /**
437      * @return whether the UI mode of the given config supports error dialogs (ANR, crash, etc).
438      * @hide
439      */
currentUiModeSupportsErrorDialogs(@onNull Configuration config)440     public static boolean currentUiModeSupportsErrorDialogs(@NonNull Configuration config) {
441         int modeType = config.uiMode & Configuration.UI_MODE_TYPE_MASK;
442         return (modeType != Configuration.UI_MODE_TYPE_CAR
443                 && !(modeType == Configuration.UI_MODE_TYPE_WATCH && Build.IS_USER)
444                 && modeType != Configuration.UI_MODE_TYPE_TELEVISION
445                 && modeType != Configuration.UI_MODE_TYPE_VR_HEADSET);
446     }
447 
448     /** @return whether the current UI mode supports error dialogs (ANR, crash, etc). */
currentUiModeSupportsErrorDialogs(@onNull Context context)449     public static boolean currentUiModeSupportsErrorDialogs(@NonNull Context context) {
450         final Configuration config = context.getResources().getConfiguration();
451         return currentUiModeSupportsErrorDialogs(config);
452     }
453 }
454