blob: c8ab260c8c4eb34acf0665b7c5f9d5c9fab2f323 [file] [log] [blame]
Aurimas Liutikasdc3f8852024-07-11 10:07:48 -07001/*
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
17package android.app;
18
19import static android.view.Display.INVALID_DISPLAY;
20
21import android.annotation.NonNull;
22import android.annotation.Nullable;
23import android.annotation.RequiresPermission;
24import android.annotation.SystemService;
25import android.annotation.TestApi;
26import android.compat.annotation.UnsupportedAppUsage;
27import android.content.Context;
28import android.content.pm.PackageManager;
29import android.content.res.Configuration;
30import android.content.res.Resources;
31import android.graphics.Rect;
32import android.os.Build;
33import android.os.IBinder;
34import android.os.Parcel;
35import android.os.Parcelable;
36import android.os.RemoteException;
37import android.os.ServiceManager;
38import android.util.DisplayMetrics;
39import android.util.Singleton;
40import android.view.RemoteAnimationDefinition;
41import android.window.SplashScreenView.SplashScreenViewParcelable;
42
43import 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)
53public 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
139 private ActivityTaskManager() {
140 }
141
142 /** @hide */
143 public static ActivityTaskManager getInstance() {
144 return sInstance.get();
145 }
146
147 /** @hide */
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)
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)
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)
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 */
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 */
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 */
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 */
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 */
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 */
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)
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)
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)
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)
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)
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 */
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). */
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. */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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)
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)
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)
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
524 public int describeContents() {
525 return 0;
526 }
527
528 @Override
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
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
564 public RootTaskInfo() {
565 }
566
567 private RootTaskInfo(Parcel source) {
568 readFromParcel(source);
569 }
570
571 @Override
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}