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