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