TaskRecord.java revision f66a83db41711ebd1187bf9e99d0b21e428075f5
1/* 2 * Copyright (C) 2006 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 com.android.server.am; 18 19import android.annotation.Nullable; 20import android.app.Activity; 21import android.app.ActivityManager; 22import android.app.ActivityManager.StackId; 23import android.app.ActivityManager.TaskDescription; 24import android.app.ActivityManager.TaskThumbnail; 25import android.app.ActivityManager.TaskThumbnailInfo; 26import android.app.ActivityOptions; 27import android.app.AppGlobals; 28import android.app.IActivityManager; 29import android.content.ComponentName; 30import android.content.Intent; 31import android.content.pm.ActivityInfo; 32import android.content.pm.ApplicationInfo; 33import android.content.pm.IPackageManager; 34import android.content.pm.PackageManager; 35import android.content.res.Configuration; 36import android.graphics.Bitmap; 37import android.graphics.Point; 38import android.graphics.Rect; 39import android.os.Debug; 40import android.os.ParcelFileDescriptor; 41import android.os.RemoteException; 42import android.os.UserHandle; 43import android.provider.Settings; 44import android.service.voice.IVoiceInteractionSession; 45import android.util.DisplayMetrics; 46import android.util.Slog; 47 48import com.android.internal.app.IVoiceInteractor; 49import com.android.internal.util.XmlUtils; 50 51import org.xmlpull.v1.XmlPullParser; 52import org.xmlpull.v1.XmlPullParserException; 53import org.xmlpull.v1.XmlSerializer; 54 55import java.io.File; 56import java.io.IOException; 57import java.io.PrintWriter; 58import java.util.ArrayList; 59import java.util.Objects; 60 61import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; 62import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 63import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; 64import static android.app.ActivityManager.StackId.HOME_STACK_ID; 65import static android.app.ActivityManager.StackId.INVALID_STACK_ID; 66import static android.app.ActivityManager.StackId.PINNED_STACK_ID; 67import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 68import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; 69import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; 70import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; 71import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; 72import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; 73import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS; 74import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 75import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; 76import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; 77import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE; 78import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; 79import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; 80import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; 81import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE; 82import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK; 83import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; 84import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS; 85import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 86import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 87import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN; 88import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; 89import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; 90import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; 91import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN; 92 93final class TaskRecord { 94 private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM; 95 private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; 96 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; 97 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK; 98 private static final String TAG_TASKS = TAG + POSTFIX_TASKS; 99 100 static final String ATTR_TASKID = "task_id"; 101 private static final String TAG_INTENT = "intent"; 102 private static final String TAG_AFFINITYINTENT = "affinity_intent"; 103 static final String ATTR_REALACTIVITY = "real_activity"; 104 static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended"; 105 private static final String ATTR_ORIGACTIVITY = "orig_activity"; 106 private static final String TAG_ACTIVITY = "activity"; 107 private static final String ATTR_AFFINITY = "affinity"; 108 private static final String ATTR_ROOT_AFFINITY = "root_affinity"; 109 private static final String ATTR_ROOTHASRESET = "root_has_reset"; 110 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents"; 111 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode"; 112 private static final String ATTR_USERID = "user_id"; 113 private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete"; 114 private static final String ATTR_EFFECTIVE_UID = "effective_uid"; 115 private static final String ATTR_TASKTYPE = "task_type"; 116 private static final String ATTR_FIRSTACTIVETIME = "first_active_time"; 117 private static final String ATTR_LASTACTIVETIME = "last_active_time"; 118 private static final String ATTR_LASTDESCRIPTION = "last_description"; 119 private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; 120 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; 121 static final String ATTR_TASK_AFFILIATION = "task_affiliation"; 122 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation"; 123 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation"; 124 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color"; 125 private static final String ATTR_CALLING_UID = "calling_uid"; 126 private static final String ATTR_CALLING_PACKAGE = "calling_package"; 127 private static final String ATTR_RESIZE_MODE = "resize_mode"; 128 private static final String ATTR_PRIVILEGED = "privileged"; 129 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds"; 130 private static final String ATTR_MIN_WIDTH = "min_width"; 131 private static final String ATTR_MIN_HEIGHT = "min_height"; 132 133 134 private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail"; 135 136 static final int INVALID_TASK_ID = -1; 137 static final int INVALID_MIN_SIZE = -1; 138 139 final int taskId; // Unique identifier for this task. 140 String affinity; // The affinity name for this task, or null; may change identity. 141 String rootAffinity; // Initial base affinity, or null; does not change from initial root. 142 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task 143 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app 144 Intent intent; // The original intent that started the task. 145 Intent affinityIntent; // Intent of affinity-moved activity that started this task. 146 int effectiveUid; // The current effective uid of the identity of this task. 147 ComponentName origActivity; // The non-alias activity component of the intent. 148 ComponentName realActivity; // The actual activity component that started the task. 149 boolean realActivitySuspended; // True if the actual activity component that started the 150 // task is suspended. 151 long firstActiveTime; // First time this task was active. 152 long lastActiveTime; // Last time this task was active, including sleep. 153 boolean inRecents; // Actually in the recents list? 154 boolean isAvailable; // Is the activity available to be launched? 155 boolean isLaunching; // Is an activity in this task launching? 156 boolean rootWasReset; // True if the intent at the root of the task had 157 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. 158 boolean autoRemoveRecents; // If true, we should automatically remove the task from 159 // recents when activity finishes 160 boolean askedCompatMode;// Have asked the user about compat mode for this task. 161 boolean hasBeenVisible; // Set if any activities in the task have been visible to the user. 162 163 String stringName; // caching of toString() result. 164 int userId; // user for which this task was created 165 boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity 166 // was changed. 167 168 int numFullscreen; // Number of fullscreen activities. 169 170 int mResizeMode; // The resize mode of this task and its activities. 171 // Based on the {@link ActivityInfo#resizeMode} of the root activity. 172 boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize 173 // changes on a temporary basis. 174 int mLockTaskMode; // Which tasklock mode to launch this task in. One of 175 // ActivityManager.LOCK_TASK_LAUNCH_MODE_* 176 private boolean mPrivileged; // The root activity application of this task holds 177 // privileged permissions. 178 179 /** Can't be put in lockTask mode. */ 180 final static int LOCK_TASK_AUTH_DONT_LOCK = 0; 181 /** Can enter app pinning with user approval. Can never start over existing lockTask task. */ 182 final static int LOCK_TASK_AUTH_PINNABLE = 1; 183 /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */ 184 final static int LOCK_TASK_AUTH_LAUNCHABLE = 2; 185 /** Can enter lockTask without user approval. Can start over existing lockTask task. */ 186 final static int LOCK_TASK_AUTH_WHITELISTED = 3; 187 /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing 188 * lockTask task. */ 189 final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4; 190 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 191 192 int mLockTaskUid = -1; // The uid of the application that called startLockTask(). 193 194 // This represents the last resolved activity values for this task 195 // NOTE: This value needs to be persisted with each task 196 TaskDescription lastTaskDescription = new TaskDescription(); 197 198 /** List of all activities in the task arranged in history order */ 199 final ArrayList<ActivityRecord> mActivities; 200 201 /** Current stack */ 202 ActivityStack stack; 203 204 /** Takes on same set of values as ActivityRecord.mActivityType */ 205 int taskType; 206 207 /** Takes on same value as first root activity */ 208 boolean isPersistable = false; 209 int maxRecents; 210 211 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for 212 * determining the order when restoring. Sign indicates whether last task movement was to front 213 * (positive) or back (negative). Absolute value indicates time. */ 214 long mLastTimeMoved = System.currentTimeMillis(); 215 216 /** Indication of what to run next when task exits. Use ActivityRecord types. 217 * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the 218 * task stack. */ 219 private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE; 220 221 /** If original intent did not allow relinquishing task identity, save that information */ 222 boolean mNeverRelinquishIdentity = true; 223 224 // Used in the unique case where we are clearing the task in order to reuse it. In that case we 225 // do not want to delete the stack when the task goes empty. 226 private boolean mReuseTask = false; 227 228 private Bitmap mLastThumbnail; // Last thumbnail captured for this item. 229 private final File mLastThumbnailFile; // File containing last thumbnail. 230 private final String mFilename; 231 private TaskThumbnailInfo mLastThumbnailInfo; 232 CharSequence lastDescription; // Last description captured for this item. 233 234 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent. 235 int mAffiliatedTaskColor; // color of the parent task affiliation. 236 TaskRecord mPrevAffiliate; // previous task in affiliated chain. 237 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence. 238 TaskRecord mNextAffiliate; // next task in affiliated chain. 239 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence. 240 241 // For relaunching the task from recents as though it was launched by the original launcher. 242 int mCallingUid; 243 String mCallingPackage; 244 245 final ActivityManagerService mService; 246 247 // Whether or not this task covers the entire screen; by default tasks are fullscreen. 248 boolean mFullscreen = true; 249 250 // Bounds of the Task. null for fullscreen tasks. 251 Rect mBounds = null; 252 private final Rect mTmpStableBounds = new Rect(); 253 private final Rect mTmpNonDecorBounds = new Rect(); 254 private final Rect mTmpRect = new Rect(); 255 private final Rect mTmpRect2 = new Rect(); 256 257 // Last non-fullscreen bounds the task was launched in or resized to. 258 // The information is persisted and used to determine the appropriate stack to launch the 259 // task into on restore. 260 Rect mLastNonFullscreenBounds = null; 261 // Minimal width and height of this task when it's resizeable. -1 means it should use the 262 // default minimal width/height. 263 int mMinWidth; 264 int mMinHeight; 265 266 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible) 267 // This number will be assigned when we evaluate OOM scores for all visible tasks. 268 int mLayerRank = -1; 269 270 Configuration mOverrideConfig = Configuration.EMPTY; 271 272 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, 273 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { 274 mService = service; 275 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 276 TaskPersister.IMAGE_EXTENSION; 277 userId = UserHandle.getUserId(info.applicationInfo.uid); 278 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename); 279 mLastThumbnailInfo = new TaskThumbnailInfo(); 280 taskId = _taskId; 281 mAffiliatedTaskId = _taskId; 282 voiceSession = _voiceSession; 283 voiceInteractor = _voiceInteractor; 284 isAvailable = true; 285 mActivities = new ArrayList<>(); 286 mCallingUid = info.applicationInfo.uid; 287 mCallingPackage = info.packageName; 288 setIntent(_intent, info); 289 setMinDimensions(info); 290 touchActiveTime(); 291 } 292 293 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, 294 TaskDescription _taskDescription, TaskThumbnailInfo thumbnailInfo) { 295 mService = service; 296 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 297 TaskPersister.IMAGE_EXTENSION; 298 userId = UserHandle.getUserId(info.applicationInfo.uid); 299 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename); 300 mLastThumbnailInfo = thumbnailInfo; 301 taskId = _taskId; 302 mAffiliatedTaskId = _taskId; 303 voiceSession = null; 304 voiceInteractor = null; 305 isAvailable = true; 306 mActivities = new ArrayList<>(); 307 mCallingUid = info.applicationInfo.uid; 308 mCallingPackage = info.packageName; 309 setIntent(_intent, info); 310 setMinDimensions(info); 311 312 taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; 313 isPersistable = true; 314 // Clamp to [1, max]. 315 maxRecents = Math.min(Math.max(info.maxRecents, 1), 316 ActivityManager.getMaxAppRecentsLimitStatic()); 317 318 taskType = APPLICATION_ACTIVITY_TYPE; 319 mTaskToReturnTo = HOME_ACTIVITY_TYPE; 320 lastTaskDescription = _taskDescription; 321 touchActiveTime(); 322 } 323 324 private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, 325 Intent _affinityIntent, String _affinity, String _rootAffinity, 326 ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, 327 boolean _autoRemoveRecents, boolean _askedCompatMode, int _taskType, int _userId, 328 int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, 329 long _firstActiveTime, long _lastActiveTime, long lastTimeMoved, 330 boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, 331 TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId, 332 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, 333 int resizeMode, boolean privileged, boolean _realActivitySuspended, 334 boolean userSetupComplete, int minWidth, int minHeight) { 335 mService = service; 336 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 337 TaskPersister.IMAGE_EXTENSION; 338 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(_userId), mFilename); 339 mLastThumbnailInfo = lastThumbnailInfo; 340 taskId = _taskId; 341 intent = _intent; 342 affinityIntent = _affinityIntent; 343 affinity = _affinity; 344 rootAffinity = _rootAffinity; 345 voiceSession = null; 346 voiceInteractor = null; 347 realActivity = _realActivity; 348 realActivitySuspended = _realActivitySuspended; 349 origActivity = _origActivity; 350 rootWasReset = _rootWasReset; 351 isAvailable = true; 352 autoRemoveRecents = _autoRemoveRecents; 353 askedCompatMode = _askedCompatMode; 354 taskType = _taskType; 355 mTaskToReturnTo = HOME_ACTIVITY_TYPE; 356 userId = _userId; 357 mUserSetupComplete = userSetupComplete; 358 effectiveUid = _effectiveUid; 359 firstActiveTime = _firstActiveTime; 360 lastActiveTime = _lastActiveTime; 361 lastDescription = _lastDescription; 362 mActivities = activities; 363 mLastTimeMoved = lastTimeMoved; 364 mNeverRelinquishIdentity = neverRelinquishIdentity; 365 lastTaskDescription = _lastTaskDescription; 366 mAffiliatedTaskId = taskAffiliation; 367 mAffiliatedTaskColor = taskAffiliationColor; 368 mPrevAffiliateTaskId = prevTaskId; 369 mNextAffiliateTaskId = nextTaskId; 370 mCallingUid = callingUid; 371 mCallingPackage = callingPackage; 372 mResizeMode = resizeMode; 373 mPrivileged = privileged; 374 mMinWidth = minWidth; 375 mMinHeight = minHeight; 376 } 377 378 void touchActiveTime() { 379 lastActiveTime = System.currentTimeMillis(); 380 if (firstActiveTime == 0) { 381 firstActiveTime = lastActiveTime; 382 } 383 } 384 385 long getInactiveDuration() { 386 return System.currentTimeMillis() - lastActiveTime; 387 } 388 389 /** Sets the original intent, and the calling uid and package. */ 390 void setIntent(ActivityRecord r) { 391 mCallingUid = r.launchedFromUid; 392 mCallingPackage = r.launchedFromPackage; 393 setIntent(r.intent, r.info); 394 } 395 396 /** Sets the original intent, _without_ updating the calling uid or package. */ 397 private void setIntent(Intent _intent, ActivityInfo info) { 398 if (intent == null) { 399 mNeverRelinquishIdentity = 400 (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0; 401 } else if (mNeverRelinquishIdentity) { 402 return; 403 } 404 405 affinity = info.taskAffinity; 406 if (intent == null) { 407 // If this task already has an intent associated with it, don't set the root 408 // affinity -- we don't want it changing after initially set, but the initially 409 // set value may be null. 410 rootAffinity = affinity; 411 } 412 effectiveUid = info.applicationInfo.uid; 413 stringName = null; 414 415 if (info.targetActivity == null) { 416 if (_intent != null) { 417 // If this Intent has a selector, we want to clear it for the 418 // recent task since it is not relevant if the user later wants 419 // to re-launch the app. 420 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) { 421 _intent = new Intent(_intent); 422 _intent.setSelector(null); 423 _intent.setSourceBounds(null); 424 } 425 } 426 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent); 427 intent = _intent; 428 realActivity = _intent != null ? _intent.getComponent() : null; 429 origActivity = null; 430 } else { 431 ComponentName targetComponent = new ComponentName( 432 info.packageName, info.targetActivity); 433 if (_intent != null) { 434 Intent targetIntent = new Intent(_intent); 435 targetIntent.setComponent(targetComponent); 436 targetIntent.setSelector(null); 437 targetIntent.setSourceBounds(null); 438 if (DEBUG_TASKS) Slog.v(TAG_TASKS, 439 "Setting Intent of " + this + " to target " + targetIntent); 440 intent = targetIntent; 441 realActivity = targetComponent; 442 origActivity = _intent.getComponent(); 443 } else { 444 intent = null; 445 realActivity = targetComponent; 446 origActivity = new ComponentName(info.packageName, info.name); 447 } 448 } 449 450 final int intentFlags = intent == null ? 0 : intent.getFlags(); 451 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 452 // Once we are set to an Intent with this flag, we count this 453 // task as having a true root activity. 454 rootWasReset = true; 455 } 456 userId = UserHandle.getUserId(info.applicationInfo.uid); 457 mUserSetupComplete = Settings.Secure.getIntForUser(mService.mContext.getContentResolver(), 458 USER_SETUP_COMPLETE, 0, userId) != 0; 459 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) { 460 // If the activity itself has requested auto-remove, then just always do it. 461 autoRemoveRecents = true; 462 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS)) 463 == FLAG_ACTIVITY_NEW_DOCUMENT) { 464 // If the caller has not asked for the document to be retained, then we may 465 // want to turn on auto-remove, depending on whether the target has set its 466 // own document launch mode. 467 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) { 468 autoRemoveRecents = false; 469 } else { 470 autoRemoveRecents = true; 471 } 472 } else { 473 autoRemoveRecents = false; 474 } 475 mResizeMode = info.resizeMode; 476 mLockTaskMode = info.lockTaskLaunchMode; 477 mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0; 478 setLockTaskAuth(); 479 } 480 481 /** Sets the original minimal width and height. */ 482 private void setMinDimensions(ActivityInfo info) { 483 if (info != null && info.windowLayout != null) { 484 mMinWidth = info.windowLayout.minWidth; 485 mMinHeight = info.windowLayout.minHeight; 486 } else { 487 mMinWidth = INVALID_MIN_SIZE; 488 mMinHeight = INVALID_MIN_SIZE; 489 } 490 } 491 492 /** 493 * Return true if the input activity has the same intent resolution as the intent this task 494 * record is based on (normally the root activity intent). 495 */ 496 boolean isSameIntentResolution(ActivityRecord r) { 497 final Intent intent = new Intent(r.intent); 498 // Correct the activity intent for aliasing. The task record intent will always be based on 499 // the real activity that will be launched not the alias, so we need to use an intent with 500 // the component name pointing to the real activity not the alias in the activity record. 501 intent.setComponent(r.realActivity); 502 return this.intent.filterEquals(intent); 503 } 504 505 void setTaskToReturnTo(int taskToReturnTo) { 506 mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE) 507 ? HOME_ACTIVITY_TYPE : taskToReturnTo; 508 } 509 510 int getTaskToReturnTo() { 511 return mTaskToReturnTo; 512 } 513 514 void setPrevAffiliate(TaskRecord prevAffiliate) { 515 mPrevAffiliate = prevAffiliate; 516 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId; 517 } 518 519 void setNextAffiliate(TaskRecord nextAffiliate) { 520 mNextAffiliate = nextAffiliate; 521 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId; 522 } 523 524 // Close up recents linked list. 525 void closeRecentsChain() { 526 if (mPrevAffiliate != null) { 527 mPrevAffiliate.setNextAffiliate(mNextAffiliate); 528 } 529 if (mNextAffiliate != null) { 530 mNextAffiliate.setPrevAffiliate(mPrevAffiliate); 531 } 532 setPrevAffiliate(null); 533 setNextAffiliate(null); 534 } 535 536 void removedFromRecents() { 537 disposeThumbnail(); 538 closeRecentsChain(); 539 if (inRecents) { 540 inRecents = false; 541 mService.notifyTaskPersisterLocked(this, false); 542 } 543 } 544 545 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) { 546 closeRecentsChain(); 547 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId; 548 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor; 549 // Find the end 550 while (taskToAffiliateWith.mNextAffiliate != null) { 551 final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate; 552 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) { 553 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId=" 554 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId); 555 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) { 556 nextRecents.setPrevAffiliate(null); 557 } 558 taskToAffiliateWith.setNextAffiliate(null); 559 break; 560 } 561 taskToAffiliateWith = nextRecents; 562 } 563 taskToAffiliateWith.setNextAffiliate(this); 564 setPrevAffiliate(taskToAffiliateWith); 565 setNextAffiliate(null); 566 } 567 568 /** 569 * Sets the last thumbnail with the current task bounds and the system orientation. 570 * @return whether the thumbnail was set 571 */ 572 boolean setLastThumbnailLocked(Bitmap thumbnail) { 573 final Configuration serviceConfig = mService.mConfiguration; 574 int taskWidth = 0; 575 int taskHeight = 0; 576 if (mBounds != null) { 577 // Non-fullscreen tasks 578 taskWidth = mBounds.width(); 579 taskHeight = mBounds.height(); 580 } else if (stack != null) { 581 // Fullscreen tasks 582 final Point displaySize = new Point(); 583 stack.getDisplaySize(displaySize); 584 taskWidth = displaySize.x; 585 taskHeight = displaySize.y; 586 } else { 587 Slog.e(TAG, "setLastThumbnailLocked() called on Task without stack"); 588 } 589 return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, serviceConfig.orientation); 590 } 591 592 /** 593 * Sets the last thumbnail with the current task bounds. 594 * @return whether the thumbnail was set 595 */ 596 private boolean setLastThumbnailLocked(Bitmap thumbnail, int taskWidth, int taskHeight, 597 int screenOrientation) { 598 if (mLastThumbnail != thumbnail) { 599 mLastThumbnail = thumbnail; 600 mLastThumbnailInfo.taskWidth = taskWidth; 601 mLastThumbnailInfo.taskHeight = taskHeight; 602 mLastThumbnailInfo.screenOrientation = screenOrientation; 603 if (thumbnail == null) { 604 if (mLastThumbnailFile != null) { 605 mLastThumbnailFile.delete(); 606 } 607 } else { 608 mService.mRecentTasks.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath()); 609 } 610 return true; 611 } 612 return false; 613 } 614 615 void getLastThumbnail(TaskThumbnail thumbs) { 616 thumbs.mainThumbnail = mLastThumbnail; 617 thumbs.thumbnailInfo = mLastThumbnailInfo; 618 thumbs.thumbnailFileDescriptor = null; 619 if (mLastThumbnail == null) { 620 thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue( 621 mLastThumbnailFile.getAbsolutePath()); 622 } 623 // Only load the thumbnail file if we don't have a thumbnail 624 if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) { 625 try { 626 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile, 627 ParcelFileDescriptor.MODE_READ_ONLY); 628 } catch (IOException e) { 629 } 630 } 631 } 632 633 /** 634 * Removes in-memory thumbnail data when the max number of in-memory task thumbnails is reached. 635 */ 636 void freeLastThumbnail() { 637 mLastThumbnail = null; 638 } 639 640 /** 641 * Removes all associated thumbnail data when a task is removed or pruned from recents. 642 */ 643 void disposeThumbnail() { 644 mLastThumbnailInfo.reset(); 645 mLastThumbnail = null; 646 lastDescription = null; 647 } 648 649 /** Returns the intent for the root activity for this task */ 650 Intent getBaseIntent() { 651 return intent != null ? intent : affinityIntent; 652 } 653 654 /** Returns the first non-finishing activity from the root. */ 655 ActivityRecord getRootActivity() { 656 for (int i = 0; i < mActivities.size(); i++) { 657 final ActivityRecord r = mActivities.get(i); 658 if (r.finishing) { 659 continue; 660 } 661 return r; 662 } 663 return null; 664 } 665 666 ActivityRecord getTopActivity() { 667 for (int i = mActivities.size() - 1; i >= 0; --i) { 668 final ActivityRecord r = mActivities.get(i); 669 if (r.finishing) { 670 continue; 671 } 672 return r; 673 } 674 return null; 675 } 676 677 ActivityRecord topRunningActivityLocked() { 678 if (stack != null) { 679 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 680 ActivityRecord r = mActivities.get(activityNdx); 681 if (!r.finishing && stack.okToShowLocked(r)) { 682 return r; 683 } 684 } 685 } 686 return null; 687 } 688 689 ActivityRecord topRunningActivityWithStartingWindowLocked() { 690 if (stack != null) { 691 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 692 ActivityRecord r = mActivities.get(activityNdx); 693 if (r.mStartingWindowState != STARTING_WINDOW_SHOWN 694 || r.finishing || !stack.okToShowLocked(r)) { 695 continue; 696 } 697 return r; 698 } 699 } 700 return null; 701 } 702 703 void setFrontOfTask() { 704 setFrontOfTask(null); 705 } 706 707 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */ 708 void setFrontOfTask(ActivityRecord newTop) { 709 // If a top candidate is suggested by the caller, go ahead and use it and mark all others 710 // as not front. This is needed in situations where the current front activity in the 711 // task isn't finished yet and we want to set the front to the activity moved to the front 712 // of the task. 713 boolean foundFront = newTop != null ? true : false; 714 715 final int numActivities = mActivities.size(); 716 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 717 final ActivityRecord r = mActivities.get(activityNdx); 718 if (foundFront || r.finishing) { 719 r.frontOfTask = false; 720 } else { 721 r.frontOfTask = true; 722 // Set frontOfTask false for every following activity. 723 foundFront = true; 724 } 725 } 726 if (!foundFront && numActivities > 0) { 727 // All activities of this task are finishing. As we ought to have a frontOfTask 728 // activity, make the bottom activity front. 729 mActivities.get(0).frontOfTask = true; 730 } 731 if (newTop != null) { 732 newTop.frontOfTask = true; 733 } 734 } 735 736 /** 737 * Reorder the history stack so that the passed activity is brought to the front. 738 */ 739 final void moveActivityToFrontLocked(ActivityRecord newTop) { 740 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, 741 "Removing and adding activity " + newTop 742 + " to stack at top callers=" + Debug.getCallers(4)); 743 744 mActivities.remove(newTop); 745 mActivities.add(newTop); 746 updateEffectiveIntent(); 747 748 setFrontOfTask(newTop); 749 } 750 751 void addActivityAtBottom(ActivityRecord r) { 752 addActivityAtIndex(0, r); 753 } 754 755 void addActivityToTop(ActivityRecord r) { 756 addActivityAtIndex(mActivities.size(), r); 757 } 758 759 void addActivityAtIndex(int index, ActivityRecord r) { 760 // Remove r first, and if it wasn't already in the list and it's fullscreen, count it. 761 if (!mActivities.remove(r) && r.fullscreen) { 762 // Was not previously in list. 763 numFullscreen++; 764 } 765 // Only set this based on the first activity 766 if (mActivities.isEmpty()) { 767 taskType = r.mActivityType; 768 isPersistable = r.isPersistable(); 769 mCallingUid = r.launchedFromUid; 770 mCallingPackage = r.launchedFromPackage; 771 // Clamp to [1, max]. 772 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 773 ActivityManager.getMaxAppRecentsLimitStatic()); 774 } else { 775 // Otherwise make all added activities match this one. 776 r.mActivityType = taskType; 777 } 778 779 final int size = mActivities.size(); 780 781 if (index == size && size > 0) { 782 final ActivityRecord top = mActivities.get(size - 1); 783 if (top.mTaskOverlay) { 784 // Place below the task overlay activity since the overlay activity should always 785 // be on top. 786 index--; 787 } 788 } 789 790 mActivities.add(index, r); 791 updateEffectiveIntent(); 792 if (r.isPersistable()) { 793 mService.notifyTaskPersisterLocked(this, false); 794 } 795 } 796 797 /** @return true if this was the last activity in the task */ 798 boolean removeActivity(ActivityRecord r) { 799 if (mActivities.remove(r) && r.fullscreen) { 800 // Was previously in list. 801 numFullscreen--; 802 } 803 if (r.isPersistable()) { 804 mService.notifyTaskPersisterLocked(this, false); 805 } 806 807 if (stack != null && stack.mStackId == PINNED_STACK_ID) { 808 // We normally notify listeners of task stack changes on pause, however pinned stack 809 // activities are normally in the paused state so no notification will be sent there 810 // before the activity is removed. We send it here so instead. 811 mService.notifyTaskStackChangedLocked(); 812 } 813 814 if (mActivities.isEmpty()) { 815 return !mReuseTask; 816 } 817 updateEffectiveIntent(); 818 return false; 819 } 820 821 boolean autoRemoveFromRecents() { 822 // We will automatically remove the task either if it has explicitly asked for 823 // this, or it is empty and has never contained an activity that got shown to 824 // the user. 825 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible); 826 } 827 828 /** 829 * Completely remove all activities associated with an existing 830 * task starting at a specified index. 831 */ 832 final void performClearTaskAtIndexLocked(int activityNdx) { 833 int numActivities = mActivities.size(); 834 for ( ; activityNdx < numActivities; ++activityNdx) { 835 final ActivityRecord r = mActivities.get(activityNdx); 836 if (r.finishing) { 837 continue; 838 } 839 if (stack == null) { 840 // Task was restored from persistent storage. 841 r.takeFromHistory(); 842 mActivities.remove(activityNdx); 843 --activityNdx; 844 --numActivities; 845 } else if (stack.finishActivityLocked( 846 r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) { 847 --activityNdx; 848 --numActivities; 849 } 850 } 851 } 852 853 /** 854 * Completely remove all activities associated with an existing task. 855 */ 856 final void performClearTaskLocked() { 857 mReuseTask = true; 858 performClearTaskAtIndexLocked(0); 859 mReuseTask = false; 860 } 861 862 ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) { 863 mReuseTask = true; 864 final ActivityRecord result = performClearTaskLocked(newR, launchFlags); 865 mReuseTask = false; 866 return result; 867 } 868 869 /** 870 * Perform clear operation as requested by 871 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 872 * stack to the given task, then look for 873 * an instance of that activity in the stack and, if found, finish all 874 * activities on top of it and return the instance. 875 * 876 * @param newR Description of the new activity being started. 877 * @return Returns the old activity that should be continued to be used, 878 * or null if none was found. 879 */ 880 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) { 881 int numActivities = mActivities.size(); 882 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) { 883 ActivityRecord r = mActivities.get(activityNdx); 884 if (r.finishing) { 885 continue; 886 } 887 if (r.realActivity.equals(newR.realActivity)) { 888 // Here it is! Now finish everything in front... 889 final ActivityRecord ret = r; 890 891 for (++activityNdx; activityNdx < numActivities; ++activityNdx) { 892 r = mActivities.get(activityNdx); 893 if (r.finishing) { 894 continue; 895 } 896 ActivityOptions opts = r.takeOptionsLocked(); 897 if (opts != null) { 898 ret.updateOptionsLocked(opts); 899 } 900 if (stack != null && stack.finishActivityLocked( 901 r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) { 902 --activityNdx; 903 --numActivities; 904 } 905 } 906 907 // Finally, if this is a normal launch mode (that is, not 908 // expecting onNewIntent()), then we will finish the current 909 // instance of the activity so a new fresh one can be started. 910 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE 911 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) { 912 if (!ret.finishing) { 913 if (stack != null) { 914 stack.finishActivityLocked( 915 ret, Activity.RESULT_CANCELED, null, "clear-task-top", false); 916 } 917 return null; 918 } 919 } 920 921 return ret; 922 } 923 } 924 925 return null; 926 } 927 928 public TaskThumbnail getTaskThumbnailLocked() { 929 if (stack != null) { 930 final ActivityRecord resumedActivity = stack.mResumedActivity; 931 if (resumedActivity != null && resumedActivity.task == this) { 932 final Bitmap thumbnail = stack.screenshotActivitiesLocked(resumedActivity); 933 setLastThumbnailLocked(thumbnail); 934 } 935 } 936 final TaskThumbnail taskThumbnail = new TaskThumbnail(); 937 getLastThumbnail(taskThumbnail); 938 return taskThumbnail; 939 } 940 941 public void removeTaskActivitiesLocked() { 942 // Just remove the entire task. 943 performClearTaskAtIndexLocked(0); 944 } 945 946 String lockTaskAuthToString() { 947 switch (mLockTaskAuth) { 948 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; 949 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; 950 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; 951 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED"; 952 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV"; 953 default: return "unknown=" + mLockTaskAuth; 954 } 955 } 956 957 void setLockTaskAuth() { 958 if (!mPrivileged && 959 (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS || 960 mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { 961 // Non-priv apps are not allowed to use always or never, fall back to default 962 mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; 963 } 964 switch (mLockTaskMode) { 965 case LOCK_TASK_LAUNCH_MODE_DEFAULT: 966 mLockTaskAuth = isLockTaskWhitelistedLocked() ? 967 LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; 968 break; 969 970 case LOCK_TASK_LAUNCH_MODE_NEVER: 971 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK; 972 break; 973 974 case LOCK_TASK_LAUNCH_MODE_ALWAYS: 975 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 976 break; 977 978 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED: 979 mLockTaskAuth = isLockTaskWhitelistedLocked() ? 980 LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; 981 break; 982 } 983 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + 984 " mLockTaskAuth=" + lockTaskAuthToString()); 985 } 986 987 boolean isLockTaskWhitelistedLocked() { 988 String pkg = (realActivity != null) ? realActivity.getPackageName() : null; 989 if (pkg == null) { 990 return false; 991 } 992 String[] packages = mService.mLockTaskPackages.get(userId); 993 if (packages == null) { 994 return false; 995 } 996 for (int i = packages.length - 1; i >= 0; --i) { 997 if (pkg.equals(packages[i])) { 998 return true; 999 } 1000 } 1001 return false; 1002 } 1003 1004 boolean isHomeTask() { 1005 return taskType == HOME_ACTIVITY_TYPE; 1006 } 1007 1008 boolean isRecentsTask() { 1009 return taskType == RECENTS_ACTIVITY_TYPE; 1010 } 1011 1012 boolean isApplicationTask() { 1013 return taskType == APPLICATION_ACTIVITY_TYPE; 1014 } 1015 1016 boolean isOverHomeStack() { 1017 return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE; 1018 } 1019 1020 boolean isResizeable() { 1021 return !isHomeTask() && (mService.mForceResizableActivities 1022 || ActivityInfo.isResizeableMode(mResizeMode)) && !mTemporarilyUnresizable; 1023 } 1024 1025 boolean inCropWindowsResizeMode() { 1026 return !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS; 1027 } 1028 1029 boolean canGoInDockedStack() { 1030 return isResizeable() || inCropWindowsResizeMode(); 1031 } 1032 1033 /** 1034 * Find the activity in the history stack within the given task. Returns 1035 * the index within the history at which it's found, or < 0 if not found. 1036 */ 1037 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) { 1038 final ComponentName realActivity = r.realActivity; 1039 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 1040 ActivityRecord candidate = mActivities.get(activityNdx); 1041 if (candidate.finishing) { 1042 continue; 1043 } 1044 if (candidate.realActivity.equals(realActivity)) { 1045 return candidate; 1046 } 1047 } 1048 return null; 1049 } 1050 1051 /** Updates the last task description values. */ 1052 void updateTaskDescription() { 1053 // Traverse upwards looking for any break between main task activities and 1054 // utility activities. 1055 int activityNdx; 1056 final int numActivities = mActivities.size(); 1057 final boolean relinquish = numActivities == 0 ? false : 1058 (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0; 1059 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; 1060 ++activityNdx) { 1061 final ActivityRecord r = mActivities.get(activityNdx); 1062 if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 1063 // This will be the top activity for determining taskDescription. Pre-inc to 1064 // overcome initial decrement below. 1065 ++activityNdx; 1066 break; 1067 } 1068 if (r.intent != null && 1069 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { 1070 break; 1071 } 1072 } 1073 if (activityNdx > 0) { 1074 // Traverse downwards starting below break looking for set label, icon. 1075 // Note that if there are activities in the task but none of them set the 1076 // recent activity values, then we do not fall back to the last set 1077 // values in the TaskRecord. 1078 String label = null; 1079 String iconFilename = null; 1080 int colorPrimary = 0; 1081 int colorBackground = 0; 1082 for (--activityNdx; activityNdx >= 0; --activityNdx) { 1083 final ActivityRecord r = mActivities.get(activityNdx); 1084 if (r.taskDescription != null) { 1085 if (label == null) { 1086 label = r.taskDescription.getLabel(); 1087 } 1088 if (iconFilename == null) { 1089 iconFilename = r.taskDescription.getIconFilename(); 1090 } 1091 if (colorPrimary == 0) { 1092 colorPrimary = r.taskDescription.getPrimaryColor(); 1093 } 1094 if (colorBackground == 0) { 1095 colorBackground = r.taskDescription.getBackgroundColor(); 1096 } 1097 } 1098 } 1099 lastTaskDescription = new TaskDescription(label, null, iconFilename, colorPrimary, 1100 colorBackground); 1101 // Update the task affiliation color if we are the parent of the group 1102 if (taskId == mAffiliatedTaskId) { 1103 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor(); 1104 } 1105 } 1106 } 1107 1108 int findEffectiveRootIndex() { 1109 int effectiveNdx = 0; 1110 final int topActivityNdx = mActivities.size() - 1; 1111 for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) { 1112 final ActivityRecord r = mActivities.get(activityNdx); 1113 if (r.finishing) { 1114 continue; 1115 } 1116 effectiveNdx = activityNdx; 1117 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 1118 break; 1119 } 1120 } 1121 return effectiveNdx; 1122 } 1123 1124 void updateEffectiveIntent() { 1125 final int effectiveRootIndex = findEffectiveRootIndex(); 1126 final ActivityRecord r = mActivities.get(effectiveRootIndex); 1127 setIntent(r); 1128 } 1129 1130 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 1131 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); 1132 1133 out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); 1134 if (realActivity != null) { 1135 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 1136 } 1137 out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended)); 1138 if (origActivity != null) { 1139 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 1140 } 1141 // Write affinity, and root affinity if it is different from affinity. 1142 // We use the special string "@" for a null root affinity, so we can identify 1143 // later whether we were given a root affinity or should just make it the 1144 // same as the affinity. 1145 if (affinity != null) { 1146 out.attribute(null, ATTR_AFFINITY, affinity); 1147 if (!affinity.equals(rootAffinity)) { 1148 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 1149 } 1150 } else if (rootAffinity != null) { 1151 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 1152 } 1153 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); 1154 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); 1155 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); 1156 out.attribute(null, ATTR_USERID, String.valueOf(userId)); 1157 out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete)); 1158 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); 1159 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType)); 1160 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime)); 1161 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime)); 1162 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); 1163 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); 1164 if (lastDescription != null) { 1165 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 1166 } 1167 if (lastTaskDescription != null) { 1168 lastTaskDescription.saveToXml(out); 1169 } 1170 mLastThumbnailInfo.saveToXml(out); 1171 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); 1172 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); 1173 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); 1174 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); 1175 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); 1176 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 1177 out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode)); 1178 out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged)); 1179 if (mLastNonFullscreenBounds != null) { 1180 out.attribute( 1181 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); 1182 } 1183 out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth)); 1184 out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight)); 1185 1186 if (affinityIntent != null) { 1187 out.startTag(null, TAG_AFFINITYINTENT); 1188 affinityIntent.saveToXml(out); 1189 out.endTag(null, TAG_AFFINITYINTENT); 1190 } 1191 1192 out.startTag(null, TAG_INTENT); 1193 intent.saveToXml(out); 1194 out.endTag(null, TAG_INTENT); 1195 1196 final ArrayList<ActivityRecord> activities = mActivities; 1197 final int numActivities = activities.size(); 1198 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 1199 final ActivityRecord r = activities.get(activityNdx); 1200 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() || 1201 ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT 1202 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) && 1203 activityNdx > 0) { 1204 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 1205 break; 1206 } 1207 out.startTag(null, TAG_ACTIVITY); 1208 r.saveToXml(out); 1209 out.endTag(null, TAG_ACTIVITY); 1210 } 1211 } 1212 1213 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 1214 throws IOException, XmlPullParserException { 1215 Intent intent = null; 1216 Intent affinityIntent = null; 1217 ArrayList<ActivityRecord> activities = new ArrayList<>(); 1218 ComponentName realActivity = null; 1219 boolean realActivitySuspended = false; 1220 ComponentName origActivity = null; 1221 String affinity = null; 1222 String rootAffinity = null; 1223 boolean hasRootAffinity = false; 1224 boolean rootHasReset = false; 1225 boolean autoRemoveRecents = false; 1226 boolean askedCompatMode = false; 1227 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; 1228 int userId = 0; 1229 boolean userSetupComplete = true; 1230 int effectiveUid = -1; 1231 String lastDescription = null; 1232 long firstActiveTime = -1; 1233 long lastActiveTime = -1; 1234 long lastTimeOnTop = 0; 1235 boolean neverRelinquishIdentity = true; 1236 int taskId = INVALID_TASK_ID; 1237 final int outerDepth = in.getDepth(); 1238 TaskDescription taskDescription = new TaskDescription(); 1239 TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo(); 1240 int taskAffiliation = INVALID_TASK_ID; 1241 int taskAffiliationColor = 0; 1242 int prevTaskId = INVALID_TASK_ID; 1243 int nextTaskId = INVALID_TASK_ID; 1244 int callingUid = -1; 1245 String callingPackage = ""; 1246 int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; 1247 boolean privileged = false; 1248 Rect bounds = null; 1249 int minWidth = INVALID_MIN_SIZE; 1250 int minHeight = INVALID_MIN_SIZE; 1251 1252 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 1253 final String attrName = in.getAttributeName(attrNdx); 1254 final String attrValue = in.getAttributeValue(attrNdx); 1255 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + 1256 attrName + " value=" + attrValue); 1257 if (ATTR_TASKID.equals(attrName)) { 1258 if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue); 1259 } else if (ATTR_REALACTIVITY.equals(attrName)) { 1260 realActivity = ComponentName.unflattenFromString(attrValue); 1261 } else if (ATTR_REALACTIVITY_SUSPENDED.equals(attrName)) { 1262 realActivitySuspended = Boolean.valueOf(attrValue); 1263 } else if (ATTR_ORIGACTIVITY.equals(attrName)) { 1264 origActivity = ComponentName.unflattenFromString(attrValue); 1265 } else if (ATTR_AFFINITY.equals(attrName)) { 1266 affinity = attrValue; 1267 } else if (ATTR_ROOT_AFFINITY.equals(attrName)) { 1268 rootAffinity = attrValue; 1269 hasRootAffinity = true; 1270 } else if (ATTR_ROOTHASRESET.equals(attrName)) { 1271 rootHasReset = Boolean.valueOf(attrValue); 1272 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) { 1273 autoRemoveRecents = Boolean.valueOf(attrValue); 1274 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) { 1275 askedCompatMode = Boolean.valueOf(attrValue); 1276 } else if (ATTR_USERID.equals(attrName)) { 1277 userId = Integer.parseInt(attrValue); 1278 } else if (ATTR_USER_SETUP_COMPLETE.equals(attrName)) { 1279 userSetupComplete = Boolean.valueOf(attrValue); 1280 } else if (ATTR_EFFECTIVE_UID.equals(attrName)) { 1281 effectiveUid = Integer.parseInt(attrValue); 1282 } else if (ATTR_TASKTYPE.equals(attrName)) { 1283 taskType = Integer.parseInt(attrValue); 1284 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) { 1285 firstActiveTime = Long.valueOf(attrValue); 1286 } else if (ATTR_LASTACTIVETIME.equals(attrName)) { 1287 lastActiveTime = Long.valueOf(attrValue); 1288 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { 1289 lastDescription = attrValue; 1290 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { 1291 lastTimeOnTop = Long.valueOf(attrValue); 1292 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { 1293 neverRelinquishIdentity = Boolean.valueOf(attrValue); 1294 } else if (attrName.startsWith(TaskThumbnailInfo.ATTR_TASK_THUMBNAILINFO_PREFIX)) { 1295 thumbnailInfo.restoreFromXml(attrName, attrValue); 1296 } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { 1297 taskDescription.restoreFromXml(attrName, attrValue); 1298 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) { 1299 taskAffiliation = Integer.parseInt(attrValue); 1300 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) { 1301 prevTaskId = Integer.parseInt(attrValue); 1302 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) { 1303 nextTaskId = Integer.parseInt(attrValue); 1304 } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) { 1305 taskAffiliationColor = Integer.parseInt(attrValue); 1306 } else if (ATTR_CALLING_UID.equals(attrName)) { 1307 callingUid = Integer.parseInt(attrValue); 1308 } else if (ATTR_CALLING_PACKAGE.equals(attrName)) { 1309 callingPackage = attrValue; 1310 } else if (ATTR_RESIZE_MODE.equals(attrName)) { 1311 resizeMode = Integer.parseInt(attrValue); 1312 resizeMode = (resizeMode == RESIZE_MODE_CROP_WINDOWS) 1313 ? RESIZE_MODE_FORCE_RESIZEABLE : resizeMode; 1314 } else if (ATTR_PRIVILEGED.equals(attrName)) { 1315 privileged = Boolean.valueOf(attrValue); 1316 } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) { 1317 bounds = Rect.unflattenFromString(attrValue); 1318 } else if (ATTR_MIN_WIDTH.equals(attrName)) { 1319 minWidth = Integer.parseInt(attrValue); 1320 } else if (ATTR_MIN_HEIGHT.equals(attrName)) { 1321 minHeight = Integer.parseInt(attrValue); 1322 } else { 1323 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); 1324 } 1325 } 1326 1327 int event; 1328 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && 1329 (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { 1330 if (event == XmlPullParser.START_TAG) { 1331 final String name = in.getName(); 1332 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + 1333 name); 1334 if (TAG_AFFINITYINTENT.equals(name)) { 1335 affinityIntent = Intent.restoreFromXml(in); 1336 } else if (TAG_INTENT.equals(name)) { 1337 intent = Intent.restoreFromXml(in); 1338 } else if (TAG_ACTIVITY.equals(name)) { 1339 ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor); 1340 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + 1341 activity); 1342 if (activity != null) { 1343 activities.add(activity); 1344 } 1345 } else { 1346 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 1347 XmlUtils.skipCurrentTag(in); 1348 } 1349 } 1350 } 1351 if (!hasRootAffinity) { 1352 rootAffinity = affinity; 1353 } else if ("@".equals(rootAffinity)) { 1354 rootAffinity = null; 1355 } 1356 if (effectiveUid <= 0) { 1357 Intent checkIntent = intent != null ? intent : affinityIntent; 1358 effectiveUid = 0; 1359 if (checkIntent != null) { 1360 IPackageManager pm = AppGlobals.getPackageManager(); 1361 try { 1362 ApplicationInfo ai = pm.getApplicationInfo( 1363 checkIntent.getComponent().getPackageName(), 1364 PackageManager.GET_UNINSTALLED_PACKAGES 1365 | PackageManager.GET_DISABLED_COMPONENTS, userId); 1366 if (ai != null) { 1367 effectiveUid = ai.uid; 1368 } 1369 } catch (RemoteException e) { 1370 } 1371 } 1372 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 1373 + ": effectiveUid=" + effectiveUid); 1374 } 1375 1376 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, 1377 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, 1378 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription, 1379 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, 1380 taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId, 1381 taskAffiliationColor, callingUid, callingPackage, resizeMode, privileged, 1382 realActivitySuspended, userSetupComplete, minWidth, minHeight); 1383 task.updateOverrideConfiguration(bounds); 1384 1385 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { 1386 activities.get(activityNdx).task = task; 1387 } 1388 1389 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); 1390 return task; 1391 } 1392 1393 private void adjustForMinimalTaskDimensions(Rect bounds) { 1394 if (bounds == null) { 1395 return; 1396 } 1397 int minWidth = mMinWidth; 1398 int minHeight = mMinHeight; 1399 // If the task has no requested minimal size, we'd like to enforce a minimal size 1400 // so that the user can not render the task too small to manipulate. We don't need 1401 // to do this for the pinned stack as the bounds are controlled by the system. 1402 if (stack.mStackId != PINNED_STACK_ID) { 1403 if (minWidth == INVALID_MIN_SIZE) { 1404 minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask; 1405 } 1406 if (minHeight == INVALID_MIN_SIZE) { 1407 minHeight = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask; 1408 } 1409 } 1410 final boolean adjustWidth = minWidth > bounds.width(); 1411 final boolean adjustHeight = minHeight > bounds.height(); 1412 if (!(adjustWidth || adjustHeight)) { 1413 return; 1414 } 1415 1416 if (adjustWidth) { 1417 if (mBounds != null && bounds.right == mBounds.right) { 1418 bounds.left = bounds.right - minWidth; 1419 } else { 1420 // Either left bounds match, or neither match, or the previous bounds were 1421 // fullscreen and we default to keeping left. 1422 bounds.right = bounds.left + minWidth; 1423 } 1424 } 1425 if (adjustHeight) { 1426 if (mBounds != null && bounds.bottom == mBounds.bottom) { 1427 bounds.top = bounds.bottom - minHeight; 1428 } else { 1429 // Either top bounds match, or neither match, or the previous bounds were 1430 // fullscreen and we default to keeping top. 1431 bounds.bottom = bounds.top + minHeight; 1432 } 1433 } 1434 } 1435 1436 /** 1437 * Update task's override configuration based on the bounds. 1438 * @param bounds The bounds of the task. 1439 * @return Update configuration or null if there is no change. 1440 */ 1441 Configuration updateOverrideConfiguration(Rect bounds) { 1442 return updateOverrideConfiguration(bounds, null /* insetBounds */); 1443 } 1444 1445 /** 1446 * Update task's override configuration based on the bounds. 1447 * @param bounds The bounds of the task. 1448 * @param insetBounds The bounds used to calculate the system insets, which is used here to 1449 * subtract the navigation bar/status bar size from the screen size reported 1450 * to the application. See {@link IActivityManager#resizeDockedStack}. 1451 * @return Update configuration or null if there is no change. 1452 */ 1453 Configuration updateOverrideConfiguration(Rect bounds, @Nullable Rect insetBounds) { 1454 if (Objects.equals(mBounds, bounds)) { 1455 return null; 1456 } 1457 final Configuration oldConfig = mOverrideConfig; 1458 final boolean oldFullscreen = mFullscreen; 1459 1460 mFullscreen = bounds == null; 1461 if (mFullscreen) { 1462 if (mBounds != null && StackId.persistTaskBounds(stack.mStackId)) { 1463 mLastNonFullscreenBounds = mBounds; 1464 } 1465 mBounds = null; 1466 mOverrideConfig = Configuration.EMPTY; 1467 } else { 1468 mTmpRect.set(bounds); 1469 adjustForMinimalTaskDimensions(mTmpRect); 1470 if (mBounds == null) { 1471 mBounds = new Rect(mTmpRect); 1472 } else { 1473 mBounds.set(mTmpRect); 1474 } 1475 if (stack == null || StackId.persistTaskBounds(stack.mStackId)) { 1476 mLastNonFullscreenBounds = mBounds; 1477 } 1478 mOverrideConfig = calculateOverrideConfig(mTmpRect, insetBounds, 1479 mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom); 1480 } 1481 1482 if (mFullscreen != oldFullscreen) { 1483 mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this); 1484 } 1485 1486 return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null; 1487 } 1488 1489 private void subtractNonDecorInsets(Rect inOutBounds, Rect inInsetBounds, 1490 boolean overrideWidth, boolean overrideHeight) { 1491 mTmpRect2.set(inInsetBounds); 1492 mService.mWindowManager.subtractNonDecorInsets(mTmpRect2); 1493 int leftInset = mTmpRect2.left - inInsetBounds.left; 1494 int topInset = mTmpRect2.top - inInsetBounds.top; 1495 int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect2.right; 1496 int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect2.bottom; 1497 inOutBounds.inset(leftInset, topInset, rightInset, bottomInset); 1498 } 1499 1500 private void subtractStableInsets(Rect inOutBounds, Rect inInsetBounds, 1501 boolean overrideWidth, boolean overrideHeight) { 1502 mTmpRect2.set(inInsetBounds); 1503 mService.mWindowManager.subtractStableInsets(mTmpRect2); 1504 int leftInset = mTmpRect2.left - inInsetBounds.left; 1505 int topInset = mTmpRect2.top - inInsetBounds.top; 1506 int rightInset = overrideWidth ? 0 : inInsetBounds.right - mTmpRect2.right; 1507 int bottomInset = overrideHeight ? 0 : inInsetBounds.bottom - mTmpRect2.bottom; 1508 inOutBounds.inset(leftInset, topInset, rightInset, bottomInset); 1509 } 1510 1511 private Configuration calculateOverrideConfig(Rect bounds, Rect insetBounds, 1512 boolean overrideWidth, boolean overrideHeight) { 1513 mTmpNonDecorBounds.set(bounds); 1514 mTmpStableBounds.set(bounds); 1515 subtractNonDecorInsets( 1516 mTmpNonDecorBounds, insetBounds != null ? insetBounds : bounds, 1517 overrideWidth, overrideHeight); 1518 subtractStableInsets( 1519 mTmpStableBounds, insetBounds != null ? insetBounds : bounds, 1520 overrideWidth, overrideHeight); 1521 1522 // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area, 1523 // i.e. the screen area without the system bars. 1524 final Configuration serviceConfig = mService.mConfiguration; 1525 final Configuration config = new Configuration(Configuration.EMPTY); 1526 // TODO(multidisplay): Update Dp to that of display stack is on. 1527 final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 1528 config.screenWidthDp = 1529 Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp); 1530 config.screenHeightDp = 1531 Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp); 1532 1533 // TODO: Orientation? 1534 config.orientation = (config.screenWidthDp <= config.screenHeightDp) 1535 ? Configuration.ORIENTATION_PORTRAIT 1536 : Configuration.ORIENTATION_LANDSCAPE; 1537 1538 // For calculating screen layout, we need to use the non-decor inset screen area for the 1539 // calculation for compatibility reasons, i.e. screen area without system bars that could 1540 // never go away in Honeycomb. 1541 final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density); 1542 final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density); 1543 final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout); 1544 final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp); 1545 final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);; 1546 config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize); 1547 1548 config.smallestScreenWidthDp = mService.mWindowManager.getSmallestWidthForTaskBounds( 1549 insetBounds != null ? insetBounds : bounds); 1550 return config; 1551 } 1552 1553 /** 1554 * Using the existing configuration {@param config}, creates a new task override config such 1555 * that all the fields that are usually set in an override config are set to the ones in 1556 * {@param config}. 1557 */ 1558 Configuration extractOverrideConfig(Configuration config) { 1559 final Configuration extracted = new Configuration(Configuration.EMPTY); 1560 extracted.screenWidthDp = config.screenWidthDp; 1561 extracted.screenHeightDp = config.screenHeightDp; 1562 extracted.smallestScreenWidthDp = config.smallestScreenWidthDp; 1563 extracted.orientation = config.orientation; 1564 extracted.screenLayout = config.screenLayout; 1565 return extracted; 1566 } 1567 1568 Rect updateOverrideConfigurationFromLaunchBounds() { 1569 final Rect bounds = validateBounds(getLaunchBounds()); 1570 updateOverrideConfiguration(bounds); 1571 if (bounds != null) { 1572 bounds.set(mBounds); 1573 } 1574 return bounds; 1575 } 1576 1577 static Rect validateBounds(Rect bounds) { 1578 if (bounds != null && bounds.isEmpty()) { 1579 Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable()); 1580 return null; 1581 } 1582 return bounds; 1583 } 1584 1585 /** Updates the task's bounds and override configuration to match what is expected for the 1586 * input stack. */ 1587 void updateOverrideConfigurationForStack(ActivityStack inStack) { 1588 if (stack != null && stack == inStack) { 1589 return; 1590 } 1591 1592 if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { 1593 if (!isResizeable()) { 1594 throw new IllegalArgumentException("Can not position non-resizeable task=" 1595 + this + " in stack=" + inStack); 1596 } 1597 if (mBounds != null) { 1598 return; 1599 } 1600 if (mLastNonFullscreenBounds != null) { 1601 updateOverrideConfiguration(mLastNonFullscreenBounds); 1602 } else { 1603 inStack.layoutTaskInStack(this, null); 1604 } 1605 } else { 1606 updateOverrideConfiguration(inStack.mBounds); 1607 } 1608 } 1609 1610 /** 1611 * Returns the correct stack to use based on task type and currently set bounds, 1612 * regardless of the focused stack and current stack association of the task. 1613 * The task will be moved (and stack focus changed) later if necessary. 1614 */ 1615 int getLaunchStackId() { 1616 if (!isApplicationTask()) { 1617 return HOME_STACK_ID; 1618 } 1619 if (mBounds != null) { 1620 return FREEFORM_WORKSPACE_STACK_ID; 1621 } 1622 return FULLSCREEN_WORKSPACE_STACK_ID; 1623 } 1624 1625 /** Returns the bounds that should be used to launch this task. */ 1626 Rect getLaunchBounds() { 1627 // If we're over lockscreen, forget about stack bounds and use fullscreen. 1628 if (mService.mLockScreenShown == LOCK_SCREEN_SHOWN) { 1629 return null; 1630 } 1631 1632 if (stack == null) { 1633 return null; 1634 } 1635 1636 final int stackId = stack.mStackId; 1637 if (stackId == HOME_STACK_ID 1638 || stackId == FULLSCREEN_WORKSPACE_STACK_ID 1639 || (stackId == DOCKED_STACK_ID && !isResizeable())) { 1640 return isResizeable() ? stack.mBounds : null; 1641 } else if (!StackId.persistTaskBounds(stackId)) { 1642 return stack.mBounds; 1643 } 1644 return mLastNonFullscreenBounds; 1645 } 1646 1647 boolean canMatchRootAffinity() { 1648 // We don't allow root affinity matching on the pinned stack as no other task should 1649 // be launching in it based on affinity. 1650 return rootAffinity != null && (stack == null || stack.mStackId != PINNED_STACK_ID); 1651 } 1652 1653 void dump(PrintWriter pw, String prefix) { 1654 pw.print(prefix); pw.print("userId="); pw.print(userId); 1655 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 1656 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 1657 pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete); 1658 pw.print(" mCallingPackage="); pw.println(mCallingPackage); 1659 if (affinity != null || rootAffinity != null) { 1660 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 1661 if (affinity == null || !affinity.equals(rootAffinity)) { 1662 pw.print(" root="); pw.println(rootAffinity); 1663 } else { 1664 pw.println(); 1665 } 1666 } 1667 if (voiceSession != null || voiceInteractor != null) { 1668 pw.print(prefix); pw.print("VOICE: session=0x"); 1669 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 1670 pw.print(" interactor=0x"); 1671 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 1672 } 1673 if (intent != null) { 1674 StringBuilder sb = new StringBuilder(128); 1675 sb.append(prefix); sb.append("intent={"); 1676 intent.toShortString(sb, false, true, false, true); 1677 sb.append('}'); 1678 pw.println(sb.toString()); 1679 } 1680 if (affinityIntent != null) { 1681 StringBuilder sb = new StringBuilder(128); 1682 sb.append(prefix); sb.append("affinityIntent={"); 1683 affinityIntent.toShortString(sb, false, true, false, true); 1684 sb.append('}'); 1685 pw.println(sb.toString()); 1686 } 1687 if (origActivity != null) { 1688 pw.print(prefix); pw.print("origActivity="); 1689 pw.println(origActivity.flattenToShortString()); 1690 } 1691 if (realActivity != null) { 1692 pw.print(prefix); pw.print("realActivity="); 1693 pw.println(realActivity.flattenToShortString()); 1694 } 1695 if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0 1696 || numFullscreen != 0) { 1697 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 1698 pw.print(" isPersistable="); pw.print(isPersistable); 1699 pw.print(" numFullscreen="); pw.print(numFullscreen); 1700 pw.print(" taskType="); pw.print(taskType); 1701 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo); 1702 } 1703 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask 1704 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { 1705 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 1706 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 1707 pw.print(" mReuseTask="); pw.print(mReuseTask); 1708 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); 1709 } 1710 if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID 1711 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID 1712 || mNextAffiliate != null) { 1713 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 1714 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 1715 pw.print(" ("); 1716 if (mPrevAffiliate == null) { 1717 pw.print("null"); 1718 } else { 1719 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 1720 } 1721 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 1722 pw.print(" ("); 1723 if (mNextAffiliate == null) { 1724 pw.print("null"); 1725 } else { 1726 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 1727 } 1728 pw.println(")"); 1729 } 1730 pw.print(prefix); pw.print("Activities="); pw.println(mActivities); 1731 if (!askedCompatMode || !inRecents || !isAvailable) { 1732 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 1733 pw.print(" inRecents="); pw.print(inRecents); 1734 pw.print(" isAvailable="); pw.println(isAvailable); 1735 } 1736 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail); 1737 pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile); 1738 if (lastDescription != null) { 1739 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 1740 } 1741 if (stack != null) { 1742 pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId); 1743 } 1744 pw.print(prefix + "hasBeenVisible=" + hasBeenVisible); 1745 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode)); 1746 pw.print(" isResizeable=" + isResizeable()); 1747 pw.print(" firstActiveTime=" + lastActiveTime); 1748 pw.print(" lastActiveTime=" + lastActiveTime); 1749 pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)"); 1750 } 1751 1752 @Override 1753 public String toString() { 1754 StringBuilder sb = new StringBuilder(128); 1755 if (stringName != null) { 1756 sb.append(stringName); 1757 sb.append(" U="); 1758 sb.append(userId); 1759 sb.append(" StackId="); 1760 sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID); 1761 sb.append(" sz="); 1762 sb.append(mActivities.size()); 1763 sb.append('}'); 1764 return sb.toString(); 1765 } 1766 sb.append("TaskRecord{"); 1767 sb.append(Integer.toHexString(System.identityHashCode(this))); 1768 sb.append(" #"); 1769 sb.append(taskId); 1770 if (affinity != null) { 1771 sb.append(" A="); 1772 sb.append(affinity); 1773 } else if (intent != null) { 1774 sb.append(" I="); 1775 sb.append(intent.getComponent().flattenToShortString()); 1776 } else if (affinityIntent != null) { 1777 sb.append(" aI="); 1778 sb.append(affinityIntent.getComponent().flattenToShortString()); 1779 } else { 1780 sb.append(" ??"); 1781 } 1782 stringName = sb.toString(); 1783 return toString(); 1784 } 1785} 1786