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