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 static android.view.Display.INVALID_DISPLAY;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SystemService;
25 import android.annotation.TestApi;
26 import android.compat.annotation.UnsupportedAppUsage;
27 import android.content.Context;
28 import android.content.pm.PackageManager;
29 import android.content.res.Configuration;
30 import android.content.res.Resources;
31 import android.graphics.Rect;
32 import android.os.Build;
33 import android.os.IBinder;
34 import android.os.Parcel;
35 import android.os.Parcelable;
36 import android.os.RemoteException;
37 import android.os.ServiceManager;
38 import android.util.DisplayMetrics;
39 import android.util.Singleton;
40 import android.view.RemoteAnimationDefinition;
41 import android.window.SplashScreenView.SplashScreenViewParcelable;
42 
43 import java.util.List;
44 
45 /**
46  * This class gives information about, and interacts with activities and their containers like task,
47  * stacks, and displays.
48  *
49  * @hide
50  */
51 @TestApi
52 @SystemService(Context.ACTIVITY_TASK_SERVICE)
53 public class ActivityTaskManager {
54 
55     /** Invalid stack ID. */
56     public static final int INVALID_STACK_ID = -1;
57 
58     /**
59      * Invalid task ID.
60      * @hide
61      */
62     public static final int INVALID_TASK_ID = -1;
63 
64     /**
65      * Invalid windowing mode.
66      * @hide
67      */
68     public static final int INVALID_WINDOWING_MODE = -1;
69 
70     /**
71      * Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
72      * that the resize doesn't need to preserve the window, and can be skipped if bounds
73      * is unchanged. This mode is used by window manager in most cases.
74      * @hide
75      */
76     public static final int RESIZE_MODE_SYSTEM = 0;
77 
78     /**
79      * Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
80      * that the resize should preserve the window if possible.
81      * @hide
82      */
83     public static final int RESIZE_MODE_PRESERVE_WINDOW   = (0x1 << 0);
84 
85     /**
86      * Input parameter to {@link IActivityTaskManager#resizeTask} used when the
87      * resize is due to a drag action.
88      * @hide
89      */
90     public static final int RESIZE_MODE_USER = RESIZE_MODE_PRESERVE_WINDOW;
91 
92     /**
93      * Input parameter to {@link IActivityTaskManager#resizeTask} used by window
94      * manager during a screen rotation.
95      * @hide
96      */
97     public static final int RESIZE_MODE_SYSTEM_SCREEN_ROTATION = RESIZE_MODE_PRESERVE_WINDOW;
98 
99     /**
100      * Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
101      * that the resize should be performed even if the bounds appears unchanged.
102      * @hide
103      */
104     public static final int RESIZE_MODE_FORCED = (0x1 << 1);
105 
106     /**
107      * Input parameter to {@link IActivityTaskManager#resizeTask} which indicates
108      * that the resize should preserve the window if possible, and should not be skipped
109      * even if the bounds is unchanged. Usually used to force a resizing when a drag action
110      * is ending.
111      * @hide
112      */
113     public static final int RESIZE_MODE_USER_FORCED =
114             RESIZE_MODE_PRESERVE_WINDOW | RESIZE_MODE_FORCED;
115 
116     /**
117      * Extra included on intents that contain an EXTRA_INTENT, with options that the contained
118      * intent may want to be started with.  Type is Bundle.
119      * TODO: remove once the ChooserActivity moves to systemui
120      * @hide
121      */
122     public static final String EXTRA_OPTIONS = "android.app.extra.OPTIONS";
123 
124     /**
125      * Extra included on intents that contain an EXTRA_INTENT, use this boolean value for the
126      * parameter of the same name when starting the contained intent.
127      * TODO: remove once the ChooserActivity moves to systemui
128      * @hide
129      */
130     public static final String EXTRA_IGNORE_TARGET_SECURITY =
131             "android.app.extra.EXTRA_IGNORE_TARGET_SECURITY";
132 
133     /** The minimal size of a display's long-edge needed to support split-screen multi-window. */
134     public static final int DEFAULT_MINIMAL_SPLIT_SCREEN_DISPLAY_SIZE_DP = 440;
135 
136     private static int sMaxRecentTasks = -1;
137 
138     private static final Singleton<ActivityTaskManager> sInstance =
139             new Singleton<ActivityTaskManager>() {
140                 @Override
141                 protected ActivityTaskManager create() {
142                     return new ActivityTaskManager();
143                 }
144             };
145 
ActivityTaskManager()146     private ActivityTaskManager() {
147     }
148 
149     /** @hide */
getInstance()150     public static ActivityTaskManager getInstance() {
151         return sInstance.get();
152     }
153 
154     /** @hide */
getService()155     public static IActivityTaskManager getService() {
156         return IActivityTaskManagerSingleton.get();
157     }
158 
159     @UnsupportedAppUsage(trackingBug = 129726065)
160     private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
161             new Singleton<IActivityTaskManager>() {
162                 @Override
163                 protected IActivityTaskManager create() {
164                     final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
165                     return IActivityTaskManager.Stub.asInterface(b);
166                 }
167             };
168 
169     /**
170      * Removes root tasks in the windowing modes from the system if they are of activity type
171      * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
172      */
173     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
removeRootTasksInWindowingModes(@onNull int[] windowingModes)174     public void removeRootTasksInWindowingModes(@NonNull int[] windowingModes) {
175         try {
176             getService().removeRootTasksInWindowingModes(windowingModes);
177         } catch (RemoteException e) {
178             throw e.rethrowFromSystemServer();
179         }
180     }
181 
182     /** Removes root tasks of the activity types from the system. */
183     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
removeRootTasksWithActivityTypes(@onNull int[] activityTypes)184     public void removeRootTasksWithActivityTypes(@NonNull int[] activityTypes) {
185         try {
186             getService().removeRootTasksWithActivityTypes(activityTypes);
187         } catch (RemoteException e) {
188             throw e.rethrowFromSystemServer();
189         }
190     }
191 
192     /**
193      * Removes all visible recent tasks from the system.
194      * @hide
195      */
196     @RequiresPermission(android.Manifest.permission.REMOVE_TASKS)
removeAllVisibleRecentTasks()197     public void removeAllVisibleRecentTasks() {
198         try {
199             getService().removeAllVisibleRecentTasks();
200         } catch (RemoteException e) {
201             throw e.rethrowFromSystemServer();
202         }
203     }
204 
205     /**
206      * Return the maximum number of recents entries that we will maintain and show.
207      * @hide
208      */
getMaxRecentTasksStatic()209     public static int getMaxRecentTasksStatic() {
210         if (sMaxRecentTasks < 0) {
211             return sMaxRecentTasks = ActivityManager.isLowRamDeviceStatic() ? 36 : 48;
212         }
213         return sMaxRecentTasks;
214     }
215 
216     /**
217      * Notify the server that splash screen of the given task has been copied"
218      *
219      * @param taskId Id of task to handle the material to reconstruct the splash screen view.
220      * @param parcelable Used to reconstruct the view, null means the surface is un-copyable.
221      * @hide
222      */
onSplashScreenViewCopyFinished(int taskId, @Nullable SplashScreenViewParcelable parcelable)223     public void onSplashScreenViewCopyFinished(int taskId,
224             @Nullable SplashScreenViewParcelable parcelable) {
225         try {
226             getService().onSplashScreenViewCopyFinished(taskId, parcelable);
227         } catch (RemoteException e) {
228             throw e.rethrowFromSystemServer();
229         }
230     }
231 
232     /**
233      * Return the default limit on the number of recents that an app can make.
234      * @hide
235      */
getDefaultAppRecentsLimitStatic()236     public static int getDefaultAppRecentsLimitStatic() {
237         return getMaxRecentTasksStatic() / 6;
238     }
239 
240     /**
241      * Return the maximum limit on the number of recents that an app can make.
242      * @hide
243      */
getMaxAppRecentsLimitStatic()244     public static int getMaxAppRecentsLimitStatic() {
245         return getMaxRecentTasksStatic() / 2;
246     }
247 
248     /**
249      * Returns true if the system supports at least one form of multi-window.
250      * E.g. freeform, split-screen, picture-in-picture.
251      */
supportsMultiWindow(Context context)252     public static boolean supportsMultiWindow(Context context) {
253         // On watches, multi-window is used to present essential system UI, and thus it must be
254         // supported regardless of device memory characteristics.
255         boolean isWatch = context.getPackageManager().hasSystemFeature(
256                 PackageManager.FEATURE_WATCH);
257         return (!ActivityManager.isLowRamDeviceStatic() || isWatch)
258                 && Resources.getSystem().getBoolean(
259                 com.android.internal.R.bool.config_supportsMultiWindow);
260     }
261 
262     /**
263      * Returns {@code true} if the display the context is associated with supports split screen
264      * multi-window.
265      *
266      * @throws UnsupportedOperationException if the supplied {@link Context} is not associated with
267      * a display.
268      */
supportsSplitScreenMultiWindow(Context context)269     public static boolean supportsSplitScreenMultiWindow(Context context) {
270         DisplayMetrics dm = new DisplayMetrics();
271         context.getDisplay().getRealMetrics(dm);
272 
273         int widthDp = (int) (dm.widthPixels / dm.density);
274         int heightDp = (int) (dm.heightPixels / dm.density);
275         if (Math.max(widthDp, heightDp) < DEFAULT_MINIMAL_SPLIT_SCREEN_DISPLAY_SIZE_DP) {
276             return false;
277         }
278 
279         return supportsMultiWindow(context)
280                 && Resources.getSystem().getBoolean(
281                 com.android.internal.R.bool.config_supportsSplitScreenMultiWindow);
282     }
283 
284     /**
285      * Start to enter lock task mode for given task by system(UI).
286      * @param taskId Id of task to lock.
287      */
288     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
startSystemLockTaskMode(int taskId)289     public void startSystemLockTaskMode(int taskId) {
290         try {
291             getService().startSystemLockTaskMode(taskId);
292         } catch (RemoteException e) {
293             throw e.rethrowFromSystemServer();
294         }
295     }
296 
297     /**
298      * Stop lock task mode by system(UI).
299      */
300     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
stopSystemLockTaskMode()301     public void stopSystemLockTaskMode() {
302         try {
303             getService().stopSystemLockTaskMode();
304         } catch (RemoteException e) {
305             throw e.rethrowFromSystemServer();
306         }
307     }
308 
309     /**
310      * Move task to root task with given id.
311      * @param taskId Id of the task to move.
312      * @param rootTaskId Id of the rootTask for task moving.
313      * @param toTop Whether the given task should shown to top of stack.
314      */
315     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
moveTaskToRootTask(int taskId, int rootTaskId, boolean toTop)316     public void moveTaskToRootTask(int taskId, int rootTaskId, boolean toTop) {
317         try {
318             getService().moveTaskToRootTask(taskId, rootTaskId, toTop);
319         } catch (RemoteException e) {
320             throw e.rethrowFromSystemServer();
321         }
322     }
323 
324     /**
325      * Resize task to given bounds.
326      * @param taskId Id of task to resize.
327      * @param bounds Bounds to resize task.
328      */
329     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
resizeTask(int taskId, Rect bounds)330     public void resizeTask(int taskId, Rect bounds) {
331         try {
332             getService().resizeTask(taskId, bounds, RESIZE_MODE_SYSTEM);
333         } catch (RemoteException e) {
334             throw e.rethrowFromSystemServer();
335         }
336     }
337 
338     /**
339      * Clears launch params for the given package.
340      * @param packageNames the names of the packages of which the launch params are to be cleared
341      */
342     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
clearLaunchParamsForPackages(List<String> packageNames)343     public void clearLaunchParamsForPackages(List<String> packageNames) {
344         try {
345             getService().clearLaunchParamsForPackages(packageNames);
346         } catch (RemoteException e) {
347             e.rethrowFromSystemServer();
348         }
349     }
350 
351     /**
352      * @return whether the UI mode of the given config supports error dialogs (ANR, crash, etc).
353      * @hide
354      */
currentUiModeSupportsErrorDialogs(@onNull Configuration config)355     public static boolean currentUiModeSupportsErrorDialogs(@NonNull Configuration config) {
356         int modeType = config.uiMode & Configuration.UI_MODE_TYPE_MASK;
357         return (modeType != Configuration.UI_MODE_TYPE_CAR
358                 && !(modeType == Configuration.UI_MODE_TYPE_WATCH && Build.IS_USER)
359                 && modeType != Configuration.UI_MODE_TYPE_TELEVISION
360                 && modeType != Configuration.UI_MODE_TYPE_VR_HEADSET);
361     }
362 
363     /** @return whether the current UI mode supports error dialogs (ANR, crash, etc). */
currentUiModeSupportsErrorDialogs(@onNull Context context)364     public static boolean currentUiModeSupportsErrorDialogs(@NonNull Context context) {
365         final Configuration config = context.getResources().getConfiguration();
366         return currentUiModeSupportsErrorDialogs(config);
367     }
368 
369     /** @return max allowed number of actions in picture-in-picture mode. */
getMaxNumPictureInPictureActions(@onNull Context context)370     public static int getMaxNumPictureInPictureActions(@NonNull Context context) {
371         return context.getResources().getInteger(
372                 com.android.internal.R.integer.config_pictureInPictureMaxNumberOfActions);
373     }
374 
375     /**
376      * @return List of running tasks.
377      * @hide
378      */
getTasks(int maxNum)379     public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
380         return getTasks(maxNum, false /* filterForVisibleRecents */, false /* keepIntentExtra */,
381                 INVALID_DISPLAY);
382     }
383 
384     /**
385      * @return List of running tasks that can be filtered by visibility in recents.
386      * @hide
387      */
getTasks( int maxNum, boolean filterOnlyVisibleRecents)388     public List<ActivityManager.RunningTaskInfo> getTasks(
389             int maxNum, boolean filterOnlyVisibleRecents) {
390         return getTasks(maxNum, filterOnlyVisibleRecents, false /* keepIntentExtra */,
391                 INVALID_DISPLAY);
392     }
393 
394     /**
395      * @return List of running tasks that can be filtered by visibility in recents and keep intent
396      * extra.
397      * @hide
398      */
getTasks( int maxNum, boolean filterOnlyVisibleRecents, boolean keepIntentExtra)399     public List<ActivityManager.RunningTaskInfo> getTasks(
400             int maxNum, boolean filterOnlyVisibleRecents, boolean keepIntentExtra) {
401         return getTasks(maxNum, filterOnlyVisibleRecents, keepIntentExtra, INVALID_DISPLAY);
402     }
403 
404     /**
405      * @return List of running tasks that can be filtered by visibility and displayId in recents
406      * and keep intent extra.
407      * @param displayId the target display id, or {@link INVALID_DISPLAY} not to filter by displayId
408      * @hide
409      */
getTasks( int maxNum, boolean filterOnlyVisibleRecents, boolean keepIntentExtra, int displayId)410     public List<ActivityManager.RunningTaskInfo> getTasks(
411             int maxNum, boolean filterOnlyVisibleRecents, boolean keepIntentExtra, int displayId) {
412         try {
413             return getService().getTasks(maxNum, filterOnlyVisibleRecents, keepIntentExtra,
414                     displayId);
415         } catch (RemoteException e) {
416             throw e.rethrowFromSystemServer();
417         }
418     }
419 
420     /**
421      * @return List of recent tasks.
422      * @hide
423      */
getRecentTasks( int maxNum, int flags, int userId)424     public List<ActivityManager.RecentTaskInfo> getRecentTasks(
425             int maxNum, int flags, int userId) {
426         try {
427             return getService().getRecentTasks(maxNum, flags, userId).getList();
428         } catch (RemoteException e) {
429             throw e.rethrowFromSystemServer();
430         }
431     }
432 
433     /** @hide */
registerTaskStackListener(TaskStackListener listener)434     public void registerTaskStackListener(TaskStackListener listener) {
435         try {
436             getService().registerTaskStackListener(listener);
437         } catch (RemoteException e) {
438             throw e.rethrowFromSystemServer();
439         }
440     }
441 
442     /** @hide */
unregisterTaskStackListener(TaskStackListener listener)443     public void unregisterTaskStackListener(TaskStackListener listener) {
444         try {
445             getService().unregisterTaskStackListener(listener);
446         } catch (RemoteException e) {
447             throw e.rethrowFromSystemServer();
448         }
449     }
450 
451     /** @hide */
getTaskBounds(int taskId)452     public Rect getTaskBounds(int taskId) {
453         try {
454             return getService().getTaskBounds(taskId);
455         } catch (RemoteException e) {
456             throw e.rethrowFromSystemServer();
457         }
458     }
459 
460     /**
461      * Registers remote animations for a display.
462      * @hide
463      */
registerRemoteAnimationsForDisplay( int displayId, RemoteAnimationDefinition definition)464     public void registerRemoteAnimationsForDisplay(
465             int displayId, RemoteAnimationDefinition definition) {
466         try {
467             getService().registerRemoteAnimationsForDisplay(displayId, definition);
468         } catch (RemoteException e) {
469             throw e.rethrowFromSystemServer();
470         }
471     }
472 
473     /** @hide */
isInLockTaskMode()474     public boolean isInLockTaskMode() {
475         try {
476             return getService().isInLockTaskMode();
477         } catch (RemoteException e) {
478             throw e.rethrowFromSystemServer();
479         }
480     }
481 
482     /** Removes task by a given taskId */
483     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
removeTask(int taskId)484     public boolean removeTask(int taskId) {
485         try {
486             return getService().removeTask(taskId);
487         } catch (RemoteException e) {
488             throw e.rethrowFromSystemServer();
489         }
490     }
491 
492     /**
493      * Detaches the navigation bar from the app it was attached to during a transition.
494      * @hide
495      */
496     @RequiresPermission(android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
detachNavigationBarFromApp(@onNull IBinder transition)497     public void detachNavigationBarFromApp(@NonNull IBinder transition) {
498         try {
499             getService().detachNavigationBarFromApp(transition);
500         } catch (RemoteException e) {
501             throw e.rethrowFromSystemServer();
502         }
503     }
504 
505     /** Update the list of packages allowed in lock task mode. */
506     @RequiresPermission(android.Manifest.permission.UPDATE_LOCK_TASK_PACKAGES)
updateLockTaskPackages(@onNull Context context, @NonNull String[] packages)507     public void updateLockTaskPackages(@NonNull Context context, @NonNull String[] packages) {
508         try {
509             getService().updateLockTaskPackages(context.getUserId(), packages);
510         } catch (RemoteException e) {
511             throw e.rethrowFromSystemServer();
512         }
513     }
514 
515     /**
516      * Information you can retrieve about a root task in the system.
517      * @hide
518      */
519     public static class RootTaskInfo extends TaskInfo implements Parcelable {
520         // TODO(b/148895075): Move some of the fields to TaskInfo.
521         public Rect bounds = new Rect();
522         public int[] childTaskIds;
523         public String[] childTaskNames;
524         public Rect[] childTaskBounds;
525         public int[] childTaskUserIds;
526         public boolean visible;
527         // Index of the stack in the display's stack list, can be used for comparison of stack order
528         public int position;
529 
530         @Override
describeContents()531         public int describeContents() {
532             return 0;
533         }
534 
535         @Override
writeToParcel(Parcel dest, int flags)536         public void writeToParcel(Parcel dest, int flags) {
537             dest.writeTypedObject(bounds, flags);
538             dest.writeIntArray(childTaskIds);
539             dest.writeStringArray(childTaskNames);
540             dest.writeTypedArray(childTaskBounds, flags);
541             dest.writeIntArray(childTaskUserIds);
542             dest.writeInt(visible ? 1 : 0);
543             dest.writeInt(position);
544             super.writeToParcel(dest, flags);
545         }
546 
547         @Override
readFromParcel(Parcel source)548         void readFromParcel(Parcel source) {
549             bounds = source.readTypedObject(Rect.CREATOR);
550             childTaskIds = source.createIntArray();
551             childTaskNames = source.createStringArray();
552             childTaskBounds = source.createTypedArray(Rect.CREATOR);
553             childTaskUserIds = source.createIntArray();
554             visible = source.readInt() > 0;
555             position = source.readInt();
556             super.readFromParcel(source);
557         }
558 
559         public static final @NonNull Creator<RootTaskInfo> CREATOR = new Creator<>() {
560             @Override
561             public RootTaskInfo createFromParcel(Parcel source) {
562                 return new RootTaskInfo(source);
563             }
564 
565             @Override
566             public RootTaskInfo[] newArray(int size) {
567                 return new RootTaskInfo[size];
568             }
569         };
570 
RootTaskInfo()571         public RootTaskInfo() {
572         }
573 
RootTaskInfo(Parcel source)574         private RootTaskInfo(Parcel source) {
575             readFromParcel(source);
576         }
577 
578         @Override
toString()579         public String toString() {
580             StringBuilder sb = new StringBuilder(256);
581             sb.append("RootTask id="); sb.append(taskId);
582             sb.append(" bounds="); sb.append(bounds.toShortString());
583             sb.append(" displayId="); sb.append(displayId);
584             sb.append(" userId="); sb.append(userId);
585             sb.append("\n");
586 
587             sb.append(" configuration="); sb.append(configuration);
588             sb.append("\n");
589 
590             for (int i = 0; i < childTaskIds.length; ++i) {
591                 sb.append("  taskId="); sb.append(childTaskIds[i]);
592                 sb.append(": "); sb.append(childTaskNames[i]);
593                 if (childTaskBounds != null) {
594                     sb.append(" bounds="); sb.append(childTaskBounds[i].toShortString());
595                 }
596                 sb.append(" userId=").append(childTaskUserIds[i]);
597                 sb.append(" visible=").append(visible);
598                 if (topActivity != null) {
599                     sb.append(" topActivity=").append(topActivity);
600                 }
601                 sb.append("\n");
602             }
603             return sb.toString();
604         }
605     }
606 }
607