TaskRecord.java revision 47b20ba8f667a0cf3ed9a1e34c93dcfdfd50eacb
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 static com.android.server.am.ActivityManagerService.TAG; 20import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; 21import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; 22import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; 23import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE; 24 25import android.app.Activity; 26import android.app.ActivityManager; 27import android.app.ActivityManager.TaskThumbnail; 28import android.app.ActivityOptions; 29import android.app.AppGlobals; 30import android.content.ComponentName; 31import android.content.Intent; 32import android.content.pm.ActivityInfo; 33import android.content.pm.ApplicationInfo; 34import android.content.pm.IPackageManager; 35import android.content.pm.PackageManager; 36import android.graphics.Bitmap; 37import android.os.ParcelFileDescriptor; 38import android.os.RemoteException; 39import android.os.UserHandle; 40import android.service.voice.IVoiceInteractionSession; 41import android.util.Slog; 42import com.android.internal.app.IVoiceInteractor; 43import com.android.internal.util.XmlUtils; 44import org.xmlpull.v1.XmlPullParser; 45import org.xmlpull.v1.XmlPullParserException; 46import org.xmlpull.v1.XmlSerializer; 47 48import java.io.File; 49import java.io.IOException; 50import java.io.PrintWriter; 51import java.util.ArrayList; 52 53final class TaskRecord { 54 private static final String ATTR_TASKID = "task_id"; 55 private static final String TAG_INTENT = "intent"; 56 private static final String TAG_AFFINITYINTENT = "affinity_intent"; 57 private static final String ATTR_REALACTIVITY = "real_activity"; 58 private static final String ATTR_ORIGACTIVITY = "orig_activity"; 59 private static final String TAG_ACTIVITY = "activity"; 60 private static final String ATTR_AFFINITY = "affinity"; 61 private static final String ATTR_ROOT_AFFINITY = "root_affinity"; 62 private static final String ATTR_ROOTHASRESET = "root_has_reset"; 63 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents"; 64 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode"; 65 private static final String ATTR_USERID = "user_id"; 66 private static final String ATTR_EFFECTIVE_UID = "effective_uid"; 67 private static final String ATTR_TASKTYPE = "task_type"; 68 private static final String ATTR_FIRSTACTIVETIME = "first_active_time"; 69 private static final String ATTR_LASTACTIVETIME = "last_active_time"; 70 private static final String ATTR_LASTDESCRIPTION = "last_description"; 71 private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; 72 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; 73 private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label"; 74 private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color"; 75 private static final String ATTR_TASK_AFFILIATION = "task_affiliation"; 76 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation"; 77 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation"; 78 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color"; 79 private static final String ATTR_CALLING_UID = "calling_uid"; 80 private static final String ATTR_CALLING_PACKAGE = "calling_package"; 81 private static final String LAST_ACTIVITY_ICON_SUFFIX = "_last_activity_icon_"; 82 83 private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail"; 84 85 static final boolean IGNORE_RETURN_TO_RECENTS = true; 86 87 final int taskId; // Unique identifier for this task. 88 String affinity; // The affinity name for this task, or null; may change identity. 89 String rootAffinity; // Initial base affinity, or null; does not change from initial root. 90 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task 91 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app 92 Intent intent; // The original intent that started the task. 93 Intent affinityIntent; // Intent of affinity-moved activity that started this task. 94 int effectiveUid; // The current effective uid of the identity of this task. 95 ComponentName origActivity; // The non-alias activity component of the intent. 96 ComponentName realActivity; // The actual activity component that started the task. 97 long firstActiveTime; // First time this task was active. 98 long lastActiveTime; // Last time this task was active, including sleep. 99 boolean inRecents; // Actually in the recents list? 100 boolean isAvailable; // Is the activity available to be launched? 101 boolean rootWasReset; // True if the intent at the root of the task had 102 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. 103 boolean autoRemoveRecents; // If true, we should automatically remove the task from 104 // recents when activity finishes 105 boolean askedCompatMode;// Have asked the user about compat mode for this task. 106 boolean hasBeenVisible; // Set if any activities in the task have been visible to the user. 107 108 String stringName; // caching of toString() result. 109 int userId; // user for which this task was created 110 int creatorUid; // The app uid that originally created the task 111 112 int numFullscreen; // Number of fullscreen activities. 113 114 // This represents the last resolved activity values for this task 115 // NOTE: This value needs to be persisted with each task 116 ActivityManager.TaskDescription lastTaskDescription = 117 new ActivityManager.TaskDescription(); 118 119 /** List of all activities in the task arranged in history order */ 120 final ArrayList<ActivityRecord> mActivities; 121 122 /** Current stack */ 123 ActivityStack stack; 124 125 /** Takes on same set of values as ActivityRecord.mActivityType */ 126 int taskType; 127 128 /** Takes on same value as first root activity */ 129 boolean isPersistable = false; 130 int maxRecents; 131 132 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for 133 * determining the order when restoring. Sign indicates whether last task movement was to front 134 * (positive) or back (negative). Absolute value indicates time. */ 135 long mLastTimeMoved = System.currentTimeMillis(); 136 137 /** Indication of what to run next when task exits. Use ActivityRecord types. 138 * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the 139 * task stack. */ 140 private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE; 141 142 /** If original intent did not allow relinquishing task identity, save that information */ 143 boolean mNeverRelinquishIdentity = true; 144 145 // Used in the unique case where we are clearing the task in order to reuse it. In that case we 146 // do not want to delete the stack when the task goes empty. 147 boolean mReuseTask = false; 148 149 private Bitmap mLastThumbnail; // Last thumbnail captured for this item. 150 private final File mLastThumbnailFile; // File containing last thubmnail. 151 private final String mFilename; 152 CharSequence lastDescription; // Last description captured for this item. 153 154 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent. 155 int mAffiliatedTaskColor; // color of the parent task affiliation. 156 TaskRecord mPrevAffiliate; // previous task in affiliated chain. 157 int mPrevAffiliateTaskId = -1; // previous id for persistence. 158 TaskRecord mNextAffiliate; // next task in affiliated chain. 159 int mNextAffiliateTaskId = -1; // next id for persistence. 160 161 // For relaunching the task from recents as though it was launched by the original launcher. 162 int mCallingUid; 163 String mCallingPackage; 164 165 final ActivityManagerService mService; 166 167 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, 168 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { 169 mService = service; 170 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 171 TaskPersister.IMAGE_EXTENSION; 172 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename); 173 taskId = _taskId; 174 mAffiliatedTaskId = _taskId; 175 voiceSession = _voiceSession; 176 voiceInteractor = _voiceInteractor; 177 isAvailable = true; 178 mActivities = new ArrayList<ActivityRecord>(); 179 setIntent(_intent, info); 180 } 181 182 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, 183 ActivityManager.TaskDescription _taskDescription) { 184 mService = service; 185 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 186 TaskPersister.IMAGE_EXTENSION; 187 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename); 188 taskId = _taskId; 189 mAffiliatedTaskId = _taskId; 190 voiceSession = null; 191 voiceInteractor = null; 192 isAvailable = true; 193 mActivities = new ArrayList<ActivityRecord>(); 194 setIntent(_intent, info); 195 196 taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; 197 isPersistable = true; 198 mCallingUid = info.applicationInfo.uid; 199 mCallingPackage = info.packageName; 200 // Clamp to [1, max]. 201 maxRecents = Math.min(Math.max(info.maxRecents, 1), 202 ActivityManager.getMaxAppRecentsLimitStatic()); 203 204 taskType = APPLICATION_ACTIVITY_TYPE; 205 mTaskToReturnTo = HOME_ACTIVITY_TYPE; 206 userId = UserHandle.getUserId(info.applicationInfo.uid); 207 lastTaskDescription = _taskDescription; 208 mCallingUid = info.applicationInfo.uid; 209 mCallingPackage = info.packageName; 210 } 211 212 TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent, 213 String _affinity, String _rootAffinity, ComponentName _realActivity, 214 ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents, 215 boolean _askedCompatMode, int _taskType, int _userId, int _effectiveUid, 216 String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime, 217 long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity, 218 ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation, 219 int prevTaskId, int nextTaskId, int taskAffiliationColor, int callingUid, 220 String callingPackage) { 221 mService = service; 222 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 223 TaskPersister.IMAGE_EXTENSION; 224 mLastThumbnailFile = new File(TaskPersister.sImagesDir, mFilename); 225 taskId = _taskId; 226 intent = _intent; 227 affinityIntent = _affinityIntent; 228 affinity = _affinity; 229 rootAffinity = _affinity; 230 voiceSession = null; 231 voiceInteractor = null; 232 realActivity = _realActivity; 233 origActivity = _origActivity; 234 rootWasReset = _rootWasReset; 235 isAvailable = true; 236 autoRemoveRecents = _autoRemoveRecents; 237 askedCompatMode = _askedCompatMode; 238 taskType = _taskType; 239 mTaskToReturnTo = HOME_ACTIVITY_TYPE; 240 userId = _userId; 241 effectiveUid = _effectiveUid; 242 firstActiveTime = _firstActiveTime; 243 lastActiveTime = _lastActiveTime; 244 lastDescription = _lastDescription; 245 mActivities = activities; 246 mLastTimeMoved = lastTimeMoved; 247 mNeverRelinquishIdentity = neverRelinquishIdentity; 248 lastTaskDescription = _lastTaskDescription; 249 mAffiliatedTaskId = taskAffiliation; 250 mAffiliatedTaskColor = taskAffiliationColor; 251 mPrevAffiliateTaskId = prevTaskId; 252 mNextAffiliateTaskId = nextTaskId; 253 mCallingUid = callingUid; 254 mCallingPackage = callingPackage; 255 } 256 257 void touchActiveTime() { 258 lastActiveTime = System.currentTimeMillis(); 259 if (firstActiveTime == 0) { 260 firstActiveTime = lastActiveTime; 261 } 262 } 263 264 long getInactiveDuration() { 265 return System.currentTimeMillis() - lastActiveTime; 266 } 267 268 /** Sets the original intent, and the calling uid and package. */ 269 void setIntent(ActivityRecord r) { 270 setIntent(r.intent, r.info); 271 mCallingUid = r.launchedFromUid; 272 mCallingPackage = r.launchedFromPackage; 273 } 274 275 /** Sets the original intent, _without_ updating the calling uid or package. */ 276 private void setIntent(Intent _intent, ActivityInfo info) { 277 if (intent == null) { 278 mNeverRelinquishIdentity = 279 (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0; 280 } else if (mNeverRelinquishIdentity) { 281 return; 282 } 283 284 affinity = info.taskAffinity; 285 if (intent == null) { 286 // If this task already has an intent associated with it, don't set the root 287 // affinity -- we don't want it changing after initially set, but the initially 288 // set value may be null. 289 rootAffinity = affinity; 290 } 291 effectiveUid = info.applicationInfo.uid; 292 stringName = null; 293 294 if (info.targetActivity == null) { 295 if (_intent != null) { 296 // If this Intent has a selector, we want to clear it for the 297 // recent task since it is not relevant if the user later wants 298 // to re-launch the app. 299 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) { 300 _intent = new Intent(_intent); 301 _intent.setSelector(null); 302 _intent.setSourceBounds(null); 303 } 304 } 305 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG, 306 "Setting Intent of " + this + " to " + _intent); 307 intent = _intent; 308 realActivity = _intent != null ? _intent.getComponent() : null; 309 origActivity = null; 310 } else { 311 ComponentName targetComponent = new ComponentName( 312 info.packageName, info.targetActivity); 313 if (_intent != null) { 314 Intent targetIntent = new Intent(_intent); 315 targetIntent.setComponent(targetComponent); 316 targetIntent.setSelector(null); 317 targetIntent.setSourceBounds(null); 318 if (ActivityManagerService.DEBUG_TASKS) Slog.v(ActivityManagerService.TAG, 319 "Setting Intent of " + this + " to target " + targetIntent); 320 intent = targetIntent; 321 realActivity = targetComponent; 322 origActivity = _intent.getComponent(); 323 } else { 324 intent = null; 325 realActivity = targetComponent; 326 origActivity = new ComponentName(info.packageName, info.name); 327 } 328 } 329 330 final int intentFlags = intent == null ? 0 : intent.getFlags(); 331 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 332 // Once we are set to an Intent with this flag, we count this 333 // task as having a true root activity. 334 rootWasReset = true; 335 } 336 337 userId = UserHandle.getUserId(info.applicationInfo.uid); 338 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) { 339 // If the activity itself has requested auto-remove, then just always do it. 340 autoRemoveRecents = true; 341 } else if ((intentFlags & (Intent.FLAG_ACTIVITY_NEW_DOCUMENT 342 | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) { 343 // If the caller has not asked for the document to be retained, then we may 344 // want to turn on auto-remove, depending on whether the target has set its 345 // own document launch mode. 346 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) { 347 autoRemoveRecents = false; 348 } else { 349 autoRemoveRecents = true; 350 } 351 } else { 352 autoRemoveRecents = false; 353 } 354 } 355 356 void setTaskToReturnTo(int taskToReturnTo) { 357 if (IGNORE_RETURN_TO_RECENTS && taskToReturnTo == RECENTS_ACTIVITY_TYPE) { 358 taskToReturnTo = HOME_ACTIVITY_TYPE; 359 } 360 mTaskToReturnTo = taskToReturnTo; 361 } 362 363 int getTaskToReturnTo() { 364 return mTaskToReturnTo; 365 } 366 367 void setPrevAffiliate(TaskRecord prevAffiliate) { 368 mPrevAffiliate = prevAffiliate; 369 mPrevAffiliateTaskId = prevAffiliate == null ? -1 : prevAffiliate.taskId; 370 } 371 372 void setNextAffiliate(TaskRecord nextAffiliate) { 373 mNextAffiliate = nextAffiliate; 374 mNextAffiliateTaskId = nextAffiliate == null ? -1 : nextAffiliate.taskId; 375 } 376 377 // Close up recents linked list. 378 void closeRecentsChain() { 379 if (mPrevAffiliate != null) { 380 mPrevAffiliate.setNextAffiliate(mNextAffiliate); 381 } 382 if (mNextAffiliate != null) { 383 mNextAffiliate.setPrevAffiliate(mPrevAffiliate); 384 } 385 setPrevAffiliate(null); 386 setNextAffiliate(null); 387 } 388 389 void removedFromRecents(TaskPersister persister) { 390 disposeThumbnail(); 391 closeRecentsChain(); 392 if (inRecents) { 393 inRecents = false; 394 persister.wakeup(this, false); 395 } 396 } 397 398 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) { 399 closeRecentsChain(); 400 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId; 401 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor; 402 // Find the end 403 while (taskToAffiliateWith.mNextAffiliate != null) { 404 final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate; 405 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) { 406 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId=" 407 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId); 408 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) { 409 nextRecents.setPrevAffiliate(null); 410 } 411 taskToAffiliateWith.setNextAffiliate(null); 412 break; 413 } 414 taskToAffiliateWith = nextRecents; 415 } 416 taskToAffiliateWith.setNextAffiliate(this); 417 setPrevAffiliate(taskToAffiliateWith); 418 setNextAffiliate(null); 419 } 420 421 /** 422 * Sets the last thumbnail. 423 * @return whether the thumbnail was set 424 */ 425 boolean setLastThumbnail(Bitmap thumbnail) { 426 if (mLastThumbnail != thumbnail) { 427 mLastThumbnail = thumbnail; 428 if (thumbnail == null) { 429 if (mLastThumbnailFile != null) { 430 mLastThumbnailFile.delete(); 431 } 432 } else { 433 mService.mTaskPersister.saveImage(thumbnail, mFilename); 434 } 435 return true; 436 } 437 return false; 438 } 439 440 void getLastThumbnail(TaskThumbnail thumbs) { 441 thumbs.mainThumbnail = mLastThumbnail; 442 thumbs.thumbnailFileDescriptor = null; 443 if (mLastThumbnail == null) { 444 thumbs.mainThumbnail = mService.mTaskPersister.getThumbnail(mFilename); 445 } 446 // Only load the thumbnail file if we don't have a thumbnail 447 if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) { 448 try { 449 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile, 450 ParcelFileDescriptor.MODE_READ_ONLY); 451 } catch (IOException e) { 452 } 453 } 454 } 455 456 void freeLastThumbnail() { 457 mLastThumbnail = null; 458 } 459 460 void disposeThumbnail() { 461 mLastThumbnail = null; 462 lastDescription = null; 463 } 464 465 /** Returns the intent for the root activity for this task */ 466 Intent getBaseIntent() { 467 return intent != null ? intent : affinityIntent; 468 } 469 470 /** Returns the first non-finishing activity from the root. */ 471 ActivityRecord getRootActivity() { 472 for (int i = 0; i < mActivities.size(); i++) { 473 final ActivityRecord r = mActivities.get(i); 474 if (r.finishing) { 475 continue; 476 } 477 return r; 478 } 479 return null; 480 } 481 482 ActivityRecord getTopActivity() { 483 for (int i = mActivities.size() - 1; i >= 0; --i) { 484 final ActivityRecord r = mActivities.get(i); 485 if (r.finishing) { 486 continue; 487 } 488 return r; 489 } 490 return null; 491 } 492 493 ActivityRecord topRunningActivityLocked(ActivityRecord notTop) { 494 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 495 ActivityRecord r = mActivities.get(activityNdx); 496 if (!r.finishing && r != notTop && stack.okToShowLocked(r)) { 497 return r; 498 } 499 } 500 return null; 501 } 502 503 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */ 504 final void setFrontOfTask() { 505 boolean foundFront = false; 506 final int numActivities = mActivities.size(); 507 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 508 final ActivityRecord r = mActivities.get(activityNdx); 509 if (foundFront || r.finishing) { 510 r.frontOfTask = false; 511 } else { 512 r.frontOfTask = true; 513 // Set frontOfTask false for every following activity. 514 foundFront = true; 515 } 516 } 517 if (!foundFront && numActivities > 0) { 518 // All activities of this task are finishing. As we ought to have a frontOfTask 519 // activity, make the bottom activity front. 520 mActivities.get(0).frontOfTask = true; 521 } 522 } 523 524 /** 525 * Reorder the history stack so that the passed activity is brought to the front. 526 */ 527 final void moveActivityToFrontLocked(ActivityRecord newTop) { 528 if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop 529 + " to stack at top", new RuntimeException("here").fillInStackTrace()); 530 531 mActivities.remove(newTop); 532 mActivities.add(newTop); 533 updateEffectiveIntent(); 534 535 setFrontOfTask(); 536 } 537 538 void addActivityAtBottom(ActivityRecord r) { 539 addActivityAtIndex(0, r); 540 } 541 542 void addActivityToTop(ActivityRecord r) { 543 addActivityAtIndex(mActivities.size(), r); 544 } 545 546 void addActivityAtIndex(int index, ActivityRecord r) { 547 // Remove r first, and if it wasn't already in the list and it's fullscreen, count it. 548 if (!mActivities.remove(r) && r.fullscreen) { 549 // Was not previously in list. 550 numFullscreen++; 551 } 552 // Only set this based on the first activity 553 if (mActivities.isEmpty()) { 554 taskType = r.mActivityType; 555 isPersistable = r.isPersistable(); 556 mCallingUid = r.launchedFromUid; 557 mCallingPackage = r.launchedFromPackage; 558 // Clamp to [1, max]. 559 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 560 ActivityManager.getMaxAppRecentsLimitStatic()); 561 } else { 562 // Otherwise make all added activities match this one. 563 r.mActivityType = taskType; 564 } 565 mActivities.add(index, r); 566 updateEffectiveIntent(); 567 if (r.isPersistable()) { 568 mService.notifyTaskPersisterLocked(this, false); 569 } 570 } 571 572 /** @return true if this was the last activity in the task */ 573 boolean removeActivity(ActivityRecord r) { 574 if (mActivities.remove(r) && r.fullscreen) { 575 // Was previously in list. 576 numFullscreen--; 577 } 578 if (r.isPersistable()) { 579 mService.notifyTaskPersisterLocked(this, false); 580 } 581 if (mActivities.isEmpty()) { 582 return !mReuseTask; 583 } 584 updateEffectiveIntent(); 585 return false; 586 } 587 588 boolean autoRemoveFromRecents() { 589 // We will automatically remove the task either if it has explicitly asked for 590 // this, or it is empty and has never contained an activity that got shown to 591 // the user. 592 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible); 593 } 594 595 /** 596 * Completely remove all activities associated with an existing 597 * task starting at a specified index. 598 */ 599 final void performClearTaskAtIndexLocked(int activityNdx) { 600 int numActivities = mActivities.size(); 601 for ( ; activityNdx < numActivities; ++activityNdx) { 602 final ActivityRecord r = mActivities.get(activityNdx); 603 if (r.finishing) { 604 continue; 605 } 606 if (stack == null) { 607 // Task was restored from persistent storage. 608 r.takeFromHistory(); 609 mActivities.remove(activityNdx); 610 --activityNdx; 611 --numActivities; 612 } else if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear", 613 false)) { 614 --activityNdx; 615 --numActivities; 616 } 617 } 618 } 619 620 /** 621 * Completely remove all activities associated with an existing task. 622 */ 623 final void performClearTaskLocked() { 624 mReuseTask = true; 625 performClearTaskAtIndexLocked(0); 626 mReuseTask = false; 627 } 628 629 /** 630 * Perform clear operation as requested by 631 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 632 * stack to the given task, then look for 633 * an instance of that activity in the stack and, if found, finish all 634 * activities on top of it and return the instance. 635 * 636 * @param newR Description of the new activity being started. 637 * @return Returns the old activity that should be continued to be used, 638 * or null if none was found. 639 */ 640 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) { 641 int numActivities = mActivities.size(); 642 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) { 643 ActivityRecord r = mActivities.get(activityNdx); 644 if (r.finishing) { 645 continue; 646 } 647 if (r.realActivity.equals(newR.realActivity)) { 648 // Here it is! Now finish everything in front... 649 final ActivityRecord ret = r; 650 651 for (++activityNdx; activityNdx < numActivities; ++activityNdx) { 652 r = mActivities.get(activityNdx); 653 if (r.finishing) { 654 continue; 655 } 656 ActivityOptions opts = r.takeOptionsLocked(); 657 if (opts != null) { 658 ret.updateOptionsLocked(opts); 659 } 660 if (stack.finishActivityLocked(r, Activity.RESULT_CANCELED, null, "clear", 661 false)) { 662 --activityNdx; 663 --numActivities; 664 } 665 } 666 667 // Finally, if this is a normal launch mode (that is, not 668 // expecting onNewIntent()), then we will finish the current 669 // instance of the activity so a new fresh one can be started. 670 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE 671 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) { 672 if (!ret.finishing) { 673 stack.finishActivityLocked(ret, Activity.RESULT_CANCELED, null, 674 "clear", false); 675 return null; 676 } 677 } 678 679 return ret; 680 } 681 } 682 683 return null; 684 } 685 686 public TaskThumbnail getTaskThumbnailLocked() { 687 if (stack != null) { 688 final ActivityRecord resumedActivity = stack.mResumedActivity; 689 if (resumedActivity != null && resumedActivity.task == this) { 690 final Bitmap thumbnail = stack.screenshotActivities(resumedActivity); 691 setLastThumbnail(thumbnail); 692 } 693 } 694 final TaskThumbnail taskThumbnail = new TaskThumbnail(); 695 getLastThumbnail(taskThumbnail); 696 return taskThumbnail; 697 } 698 699 public void removeTaskActivitiesLocked() { 700 // Just remove the entire task. 701 performClearTaskAtIndexLocked(0); 702 } 703 704 boolean isHomeTask() { 705 return taskType == HOME_ACTIVITY_TYPE; 706 } 707 708 boolean isApplicationTask() { 709 return taskType == APPLICATION_ACTIVITY_TYPE; 710 } 711 712 boolean isOverHomeStack() { 713 return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE; 714 } 715 716 /** 717 * Find the activity in the history stack within the given task. Returns 718 * the index within the history at which it's found, or < 0 if not found. 719 */ 720 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) { 721 final ComponentName realActivity = r.realActivity; 722 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 723 ActivityRecord candidate = mActivities.get(activityNdx); 724 if (candidate.finishing) { 725 continue; 726 } 727 if (candidate.realActivity.equals(realActivity)) { 728 return candidate; 729 } 730 } 731 return null; 732 } 733 734 /** Updates the last task description values. */ 735 void updateTaskDescription() { 736 // Traverse upwards looking for any break between main task activities and 737 // utility activities. 738 int activityNdx; 739 final int numActivities = mActivities.size(); 740 final boolean relinquish = numActivities == 0 ? false : 741 (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0; 742 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; 743 ++activityNdx) { 744 final ActivityRecord r = mActivities.get(activityNdx); 745 if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 746 // This will be the top activity for determining taskDescription. Pre-inc to 747 // overcome initial decrement below. 748 ++activityNdx; 749 break; 750 } 751 if (r.intent != null && 752 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { 753 break; 754 } 755 } 756 if (activityNdx > 0) { 757 // Traverse downwards starting below break looking for set label, icon. 758 // Note that if there are activities in the task but none of them set the 759 // recent activity values, then we do not fall back to the last set 760 // values in the TaskRecord. 761 String label = null; 762 Bitmap icon = null; 763 int colorPrimary = 0; 764 for (--activityNdx; activityNdx >= 0; --activityNdx) { 765 final ActivityRecord r = mActivities.get(activityNdx); 766 if (r.taskDescription != null) { 767 if (label == null) { 768 label = r.taskDescription.getLabel(); 769 } 770 if (icon == null) { 771 icon = r.taskDescription.getIcon(); 772 } 773 if (colorPrimary == 0) { 774 colorPrimary = r.taskDescription.getPrimaryColor(); 775 } 776 } 777 } 778 lastTaskDescription = new ActivityManager.TaskDescription(label, icon, colorPrimary); 779 // Update the task affiliation color if we are the parent of the group 780 if (taskId == mAffiliatedTaskId) { 781 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor(); 782 } 783 } 784 } 785 786 int findEffectiveRootIndex() { 787 int activityNdx; 788 final int topActivityNdx = mActivities.size() - 1; 789 for (activityNdx = 0; activityNdx < topActivityNdx; ++activityNdx) { 790 final ActivityRecord r = mActivities.get(activityNdx); 791 if (r.finishing) { 792 continue; 793 } 794 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 795 break; 796 } 797 } 798 return activityNdx; 799 } 800 801 void updateEffectiveIntent() { 802 final int effectiveRootIndex = findEffectiveRootIndex(); 803 final ActivityRecord r = mActivities.get(effectiveRootIndex); 804 setIntent(r); 805 } 806 807 void saveTaskDescription(ActivityManager.TaskDescription taskDescription, 808 String iconFilename, XmlSerializer out) throws IOException { 809 if (taskDescription != null) { 810 final String label = taskDescription.getLabel(); 811 if (label != null) { 812 out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label); 813 } 814 final int colorPrimary = taskDescription.getPrimaryColor(); 815 if (colorPrimary != 0) { 816 out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary)); 817 } 818 final Bitmap icon = taskDescription.getIcon(); 819 if (icon != null) { 820 mService.mTaskPersister.saveImage(icon, iconFilename); 821 } 822 } 823 } 824 825 static boolean readTaskDescriptionAttribute(ActivityManager.TaskDescription taskDescription, 826 String attrName, String attrValue) { 827 if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) { 828 taskDescription.setLabel(attrValue); 829 } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) { 830 taskDescription.setPrimaryColor((int) Long.parseLong(attrValue, 16)); 831 } else { 832 return false; 833 } 834 return true; 835 } 836 837 private static String createLastTaskDescriptionIconFilename(int taskId, long lastActiveTime) { 838 return String.valueOf(taskId) + LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime + 839 TaskPersister.IMAGE_EXTENSION; 840 } 841 842 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 843 if (ActivityManagerService.DEBUG_RECENTS) Slog.i(TAG, "Saving task=" + this); 844 845 out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); 846 if (realActivity != null) { 847 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 848 } 849 if (origActivity != null) { 850 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 851 } 852 // Write affinity, and root affinity if it is different from affinity. 853 // We use the special string "@" for a null root affinity, so we can identify 854 // later whether we were given a root affinity or should just make it the 855 // same as the affinity. 856 if (affinity != null) { 857 out.attribute(null, ATTR_AFFINITY, affinity); 858 if (!affinity.equals(rootAffinity)) { 859 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 860 } 861 } else if (rootAffinity != null) { 862 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 863 } 864 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); 865 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); 866 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); 867 out.attribute(null, ATTR_USERID, String.valueOf(userId)); 868 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); 869 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType)); 870 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime)); 871 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime)); 872 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); 873 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); 874 if (lastDescription != null) { 875 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 876 } 877 if (lastTaskDescription != null) { 878 saveTaskDescription(lastTaskDescription, createLastTaskDescriptionIconFilename(taskId, 879 lastActiveTime), out); 880 } 881 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); 882 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); 883 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); 884 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); 885 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); 886 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 887 888 if (affinityIntent != null) { 889 out.startTag(null, TAG_AFFINITYINTENT); 890 affinityIntent.saveToXml(out); 891 out.endTag(null, TAG_AFFINITYINTENT); 892 } 893 894 out.startTag(null, TAG_INTENT); 895 intent.saveToXml(out); 896 out.endTag(null, TAG_INTENT); 897 898 final ArrayList<ActivityRecord> activities = mActivities; 899 final int numActivities = activities.size(); 900 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 901 final ActivityRecord r = activities.get(activityNdx); 902 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() || 903 ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) && 904 activityNdx > 0) { 905 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 906 break; 907 } 908 out.startTag(null, TAG_ACTIVITY); 909 r.saveToXml(out); 910 out.endTag(null, TAG_ACTIVITY); 911 } 912 } 913 914 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 915 throws IOException, XmlPullParserException { 916 Intent intent = null; 917 Intent affinityIntent = null; 918 ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); 919 ComponentName realActivity = null; 920 ComponentName origActivity = null; 921 String affinity = null; 922 String rootAffinity = null; 923 boolean hasRootAffinity = false; 924 boolean rootHasReset = false; 925 boolean autoRemoveRecents = false; 926 boolean askedCompatMode = false; 927 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; 928 int userId = 0; 929 int effectiveUid = -1; 930 String lastDescription = null; 931 long firstActiveTime = -1; 932 long lastActiveTime = -1; 933 long lastTimeOnTop = 0; 934 boolean neverRelinquishIdentity = true; 935 int taskId = -1; 936 final int outerDepth = in.getDepth(); 937 ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription(); 938 int taskAffiliation = -1; 939 int taskAffiliationColor = 0; 940 int prevTaskId = -1; 941 int nextTaskId = -1; 942 int callingUid = -1; 943 String callingPackage = ""; 944 945 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 946 final String attrName = in.getAttributeName(attrNdx); 947 final String attrValue = in.getAttributeValue(attrNdx); 948 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + 949 attrName + " value=" + attrValue); 950 if (ATTR_TASKID.equals(attrName)) { 951 taskId = Integer.valueOf(attrValue); 952 } else if (ATTR_REALACTIVITY.equals(attrName)) { 953 realActivity = ComponentName.unflattenFromString(attrValue); 954 } else if (ATTR_ORIGACTIVITY.equals(attrName)) { 955 origActivity = ComponentName.unflattenFromString(attrValue); 956 } else if (ATTR_AFFINITY.equals(attrName)) { 957 affinity = attrValue; 958 } else if (ATTR_ROOT_AFFINITY.equals(attrName)) { 959 rootAffinity = attrValue; 960 hasRootAffinity = true; 961 } else if (ATTR_ROOTHASRESET.equals(attrName)) { 962 rootHasReset = Boolean.valueOf(attrValue); 963 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) { 964 autoRemoveRecents = Boolean.valueOf(attrValue); 965 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) { 966 askedCompatMode = Boolean.valueOf(attrValue); 967 } else if (ATTR_USERID.equals(attrName)) { 968 userId = Integer.valueOf(attrValue); 969 } else if (ATTR_EFFECTIVE_UID.equals(attrName)) { 970 effectiveUid = Integer.valueOf(attrValue); 971 } else if (ATTR_TASKTYPE.equals(attrName)) { 972 taskType = Integer.valueOf(attrValue); 973 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) { 974 firstActiveTime = Long.valueOf(attrValue); 975 } else if (ATTR_LASTACTIVETIME.equals(attrName)) { 976 lastActiveTime = Long.valueOf(attrValue); 977 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { 978 lastDescription = attrValue; 979 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { 980 lastTimeOnTop = Long.valueOf(attrValue); 981 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { 982 neverRelinquishIdentity = Boolean.valueOf(attrValue); 983 } else if (readTaskDescriptionAttribute(taskDescription, attrName, attrValue)) { 984 // Completed in TaskPersister.readTaskDescriptionAttribute() 985 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) { 986 taskAffiliation = Integer.valueOf(attrValue); 987 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) { 988 prevTaskId = Integer.valueOf(attrValue); 989 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) { 990 nextTaskId = Integer.valueOf(attrValue); 991 } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) { 992 taskAffiliationColor = Integer.valueOf(attrValue); 993 } else if (ATTR_CALLING_UID.equals(attrName)) { 994 callingUid = Integer.valueOf(attrValue); 995 } else if (ATTR_CALLING_PACKAGE.equals(attrName)) { 996 callingPackage = attrValue; 997 } else { 998 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); 999 } 1000 } 1001 1002 int event; 1003 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && 1004 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { 1005 if (event == XmlPullParser.START_TAG) { 1006 final String name = in.getName(); 1007 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + 1008 name); 1009 if (TAG_AFFINITYINTENT.equals(name)) { 1010 affinityIntent = Intent.restoreFromXml(in); 1011 } else if (TAG_INTENT.equals(name)) { 1012 intent = Intent.restoreFromXml(in); 1013 } else if (TAG_ACTIVITY.equals(name)) { 1014 ActivityRecord activity = 1015 ActivityRecord.restoreFromXml(in, taskId, stackSupervisor); 1016 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + 1017 activity); 1018 if (activity != null) { 1019 activities.add(activity); 1020 } 1021 } else { 1022 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 1023 XmlUtils.skipCurrentTag(in); 1024 } 1025 } 1026 } 1027 1028 if (lastActiveTime >= 0) { 1029 taskDescription.setIcon(TaskPersister.restoreImage( 1030 createLastTaskDescriptionIconFilename(taskId, lastActiveTime))); 1031 } 1032 1033 if (!hasRootAffinity) { 1034 rootAffinity = affinity; 1035 } else if ("@".equals(rootAffinity)) { 1036 rootAffinity = null; 1037 } 1038 1039 if (effectiveUid <= 0) { 1040 Intent checkIntent = intent != null ? intent : affinityIntent; 1041 effectiveUid = 0; 1042 if (checkIntent != null) { 1043 IPackageManager pm = AppGlobals.getPackageManager(); 1044 try { 1045 ApplicationInfo ai = pm.getApplicationInfo( 1046 checkIntent.getComponent().getPackageName(), 1047 PackageManager.GET_UNINSTALLED_PACKAGES 1048 | PackageManager.GET_DISABLED_COMPONENTS, userId); 1049 if (ai != null) { 1050 effectiveUid = ai.uid; 1051 } 1052 } catch (RemoteException e) { 1053 } 1054 } 1055 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 1056 + ": effectiveUid=" + effectiveUid); 1057 } 1058 1059 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, 1060 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, 1061 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription, 1062 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, 1063 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, 1064 callingUid, callingPackage); 1065 1066 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { 1067 activities.get(activityNdx).task = task; 1068 } 1069 1070 if (ActivityManagerService.DEBUG_RECENTS) Slog.d(TAG, "Restored task=" + task); 1071 return task; 1072 } 1073 1074 void dump(PrintWriter pw, String prefix) { 1075 pw.print(prefix); pw.print("userId="); pw.print(userId); 1076 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 1077 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 1078 pw.print(" mCallingPackage="); pw.println(mCallingPackage); 1079 if (affinity != null || rootAffinity != null) { 1080 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 1081 if (affinity == null || !affinity.equals(rootAffinity)) { 1082 pw.print(" root="); pw.println(rootAffinity); 1083 } else { 1084 pw.println(); 1085 } 1086 } 1087 if (voiceSession != null || voiceInteractor != null) { 1088 pw.print(prefix); pw.print("VOICE: session=0x"); 1089 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 1090 pw.print(" interactor=0x"); 1091 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 1092 } 1093 if (intent != null) { 1094 StringBuilder sb = new StringBuilder(128); 1095 sb.append(prefix); sb.append("intent={"); 1096 intent.toShortString(sb, false, true, false, true); 1097 sb.append('}'); 1098 pw.println(sb.toString()); 1099 } 1100 if (affinityIntent != null) { 1101 StringBuilder sb = new StringBuilder(128); 1102 sb.append(prefix); sb.append("affinityIntent={"); 1103 affinityIntent.toShortString(sb, false, true, false, true); 1104 sb.append('}'); 1105 pw.println(sb.toString()); 1106 } 1107 if (origActivity != null) { 1108 pw.print(prefix); pw.print("origActivity="); 1109 pw.println(origActivity.flattenToShortString()); 1110 } 1111 if (realActivity != null) { 1112 pw.print(prefix); pw.print("realActivity="); 1113 pw.println(realActivity.flattenToShortString()); 1114 } 1115 if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0 1116 || numFullscreen != 0) { 1117 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 1118 pw.print(" isPersistable="); pw.print(isPersistable); 1119 pw.print(" numFullscreen="); pw.print(numFullscreen); 1120 pw.print(" taskType="); pw.print(taskType); 1121 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo); 1122 } 1123 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask) { 1124 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 1125 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 1126 pw.print(" mReuseTask="); pw.println(mReuseTask); 1127 } 1128 if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != -1 || mPrevAffiliate != null 1129 || mNextAffiliateTaskId != -1 || mNextAffiliate != null) { 1130 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 1131 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 1132 pw.print(" ("); 1133 if (mPrevAffiliate == null) { 1134 pw.print("null"); 1135 } else { 1136 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 1137 } 1138 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 1139 pw.print(" ("); 1140 if (mNextAffiliate == null) { 1141 pw.print("null"); 1142 } else { 1143 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 1144 } 1145 pw.println(")"); 1146 } 1147 pw.print(prefix); pw.print("Activities="); pw.println(mActivities); 1148 if (!askedCompatMode || !inRecents || !isAvailable) { 1149 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 1150 pw.print(" inRecents="); pw.print(inRecents); 1151 pw.print(" isAvailable="); pw.println(isAvailable); 1152 } 1153 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail); 1154 pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile); 1155 if (lastDescription != null) { 1156 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 1157 } 1158 pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible); 1159 pw.print(" firstActiveTime="); pw.print(lastActiveTime); 1160 pw.print(" lastActiveTime="); pw.print(lastActiveTime); 1161 pw.print(" (inactive for "); 1162 pw.print((getInactiveDuration()/1000)); pw.println("s)"); 1163 } 1164 1165 @Override 1166 public String toString() { 1167 StringBuilder sb = new StringBuilder(128); 1168 if (stringName != null) { 1169 sb.append(stringName); 1170 sb.append(" U="); 1171 sb.append(userId); 1172 sb.append(" sz="); 1173 sb.append(mActivities.size()); 1174 sb.append('}'); 1175 return sb.toString(); 1176 } 1177 sb.append("TaskRecord{"); 1178 sb.append(Integer.toHexString(System.identityHashCode(this))); 1179 sb.append(" #"); 1180 sb.append(taskId); 1181 if (affinity != null) { 1182 sb.append(" A="); 1183 sb.append(affinity); 1184 } else if (intent != null) { 1185 sb.append(" I="); 1186 sb.append(intent.getComponent().flattenToShortString()); 1187 } else if (affinityIntent != null) { 1188 sb.append(" aI="); 1189 sb.append(affinityIntent.getComponent().flattenToShortString()); 1190 } else { 1191 sb.append(" ??"); 1192 } 1193 stringName = sb.toString(); 1194 return toString(); 1195 } 1196} 1197