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