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