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