TaskRecord.java revision 4767f4b3a97ce468c6ef9abf8fb06e0b8051dba1
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 if (intent != null && 331 (intent.getFlags()&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 ((intent.getFlags()&(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 effectiveNdx = 0; 788 final int topActivityNdx = mActivities.size() - 1; 789 for (int activityNdx = 0; activityNdx < topActivityNdx; ++activityNdx) { 790 final ActivityRecord r = mActivities.get(activityNdx); 791 if (r.finishing) { 792 continue; 793 } 794 effectiveNdx = activityNdx; 795 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 796 break; 797 } 798 } 799 return effectiveNdx; 800 } 801 802 void updateEffectiveIntent() { 803 final int effectiveRootIndex = findEffectiveRootIndex(); 804 final ActivityRecord r = mActivities.get(effectiveRootIndex); 805 setIntent(r); 806 } 807 808 void saveTaskDescription(ActivityManager.TaskDescription taskDescription, 809 String iconFilename, XmlSerializer out) throws IOException { 810 if (taskDescription != null) { 811 final String label = taskDescription.getLabel(); 812 if (label != null) { 813 out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label); 814 } 815 final int colorPrimary = taskDescription.getPrimaryColor(); 816 if (colorPrimary != 0) { 817 out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary)); 818 } 819 final Bitmap icon = taskDescription.getIcon(); 820 if (icon != null) { 821 mService.mTaskPersister.saveImage(icon, iconFilename); 822 } 823 } 824 } 825 826 static boolean readTaskDescriptionAttribute(ActivityManager.TaskDescription taskDescription, 827 String attrName, String attrValue) { 828 if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) { 829 taskDescription.setLabel(attrValue); 830 } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) { 831 taskDescription.setPrimaryColor((int) Long.parseLong(attrValue, 16)); 832 } else { 833 return false; 834 } 835 return true; 836 } 837 838 private static String createLastTaskDescriptionIconFilename(int taskId, long lastActiveTime) { 839 return String.valueOf(taskId) + LAST_ACTIVITY_ICON_SUFFIX + lastActiveTime + 840 TaskPersister.IMAGE_EXTENSION; 841 } 842 843 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 844 if (ActivityManagerService.DEBUG_RECENTS) Slog.i(TAG, "Saving task=" + this); 845 846 out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); 847 if (realActivity != null) { 848 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 849 } 850 if (origActivity != null) { 851 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 852 } 853 // Write affinity, and root affinity if it is different from affinity. 854 // We use the special string "@" for a null root affinity, so we can identify 855 // later whether we were given a root affinity or should just make it the 856 // same as the affinity. 857 if (affinity != null) { 858 out.attribute(null, ATTR_AFFINITY, affinity); 859 if (!affinity.equals(rootAffinity)) { 860 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 861 } 862 } else if (rootAffinity != null) { 863 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 864 } 865 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); 866 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); 867 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); 868 out.attribute(null, ATTR_USERID, String.valueOf(userId)); 869 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); 870 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType)); 871 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime)); 872 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime)); 873 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); 874 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); 875 if (lastDescription != null) { 876 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 877 } 878 if (lastTaskDescription != null) { 879 saveTaskDescription(lastTaskDescription, createLastTaskDescriptionIconFilename(taskId, 880 lastActiveTime), out); 881 } 882 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); 883 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); 884 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); 885 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); 886 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); 887 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 888 889 if (affinityIntent != null) { 890 out.startTag(null, TAG_AFFINITYINTENT); 891 affinityIntent.saveToXml(out); 892 out.endTag(null, TAG_AFFINITYINTENT); 893 } 894 895 out.startTag(null, TAG_INTENT); 896 intent.saveToXml(out); 897 out.endTag(null, TAG_INTENT); 898 899 final ArrayList<ActivityRecord> activities = mActivities; 900 final int numActivities = activities.size(); 901 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 902 final ActivityRecord r = activities.get(activityNdx); 903 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() || 904 ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) && 905 activityNdx > 0) { 906 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 907 break; 908 } 909 out.startTag(null, TAG_ACTIVITY); 910 r.saveToXml(out); 911 out.endTag(null, TAG_ACTIVITY); 912 } 913 } 914 915 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 916 throws IOException, XmlPullParserException { 917 Intent intent = null; 918 Intent affinityIntent = null; 919 ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); 920 ComponentName realActivity = null; 921 ComponentName origActivity = null; 922 String affinity = null; 923 String rootAffinity = null; 924 boolean hasRootAffinity = false; 925 boolean rootHasReset = false; 926 boolean autoRemoveRecents = false; 927 boolean askedCompatMode = false; 928 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; 929 int userId = 0; 930 int effectiveUid = -1; 931 String lastDescription = null; 932 long firstActiveTime = -1; 933 long lastActiveTime = -1; 934 long lastTimeOnTop = 0; 935 boolean neverRelinquishIdentity = true; 936 int taskId = -1; 937 final int outerDepth = in.getDepth(); 938 ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription(); 939 int taskAffiliation = -1; 940 int taskAffiliationColor = 0; 941 int prevTaskId = -1; 942 int nextTaskId = -1; 943 int callingUid = -1; 944 String callingPackage = ""; 945 946 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 947 final String attrName = in.getAttributeName(attrNdx); 948 final String attrValue = in.getAttributeValue(attrNdx); 949 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + 950 attrName + " value=" + attrValue); 951 if (ATTR_TASKID.equals(attrName)) { 952 taskId = Integer.valueOf(attrValue); 953 } else if (ATTR_REALACTIVITY.equals(attrName)) { 954 realActivity = ComponentName.unflattenFromString(attrValue); 955 } else if (ATTR_ORIGACTIVITY.equals(attrName)) { 956 origActivity = ComponentName.unflattenFromString(attrValue); 957 } else if (ATTR_AFFINITY.equals(attrName)) { 958 affinity = attrValue; 959 } else if (ATTR_ROOT_AFFINITY.equals(attrName)) { 960 rootAffinity = attrValue; 961 hasRootAffinity = true; 962 } else if (ATTR_ROOTHASRESET.equals(attrName)) { 963 rootHasReset = Boolean.valueOf(attrValue); 964 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) { 965 autoRemoveRecents = Boolean.valueOf(attrValue); 966 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) { 967 askedCompatMode = Boolean.valueOf(attrValue); 968 } else if (ATTR_USERID.equals(attrName)) { 969 userId = Integer.valueOf(attrValue); 970 } else if (ATTR_EFFECTIVE_UID.equals(attrName)) { 971 effectiveUid = Integer.valueOf(attrValue); 972 } else if (ATTR_TASKTYPE.equals(attrName)) { 973 taskType = Integer.valueOf(attrValue); 974 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) { 975 firstActiveTime = Long.valueOf(attrValue); 976 } else if (ATTR_LASTACTIVETIME.equals(attrName)) { 977 lastActiveTime = Long.valueOf(attrValue); 978 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { 979 lastDescription = attrValue; 980 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { 981 lastTimeOnTop = Long.valueOf(attrValue); 982 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { 983 neverRelinquishIdentity = Boolean.valueOf(attrValue); 984 } else if (readTaskDescriptionAttribute(taskDescription, attrName, attrValue)) { 985 // Completed in TaskPersister.readTaskDescriptionAttribute() 986 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) { 987 taskAffiliation = Integer.valueOf(attrValue); 988 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) { 989 prevTaskId = Integer.valueOf(attrValue); 990 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) { 991 nextTaskId = Integer.valueOf(attrValue); 992 } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) { 993 taskAffiliationColor = Integer.valueOf(attrValue); 994 } else if (ATTR_CALLING_UID.equals(attrName)) { 995 callingUid = Integer.valueOf(attrValue); 996 } else if (ATTR_CALLING_PACKAGE.equals(attrName)) { 997 callingPackage = attrValue; 998 } else { 999 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); 1000 } 1001 } 1002 1003 int event; 1004 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && 1005 (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) { 1006 if (event == XmlPullParser.START_TAG) { 1007 final String name = in.getName(); 1008 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + 1009 name); 1010 if (TAG_AFFINITYINTENT.equals(name)) { 1011 affinityIntent = Intent.restoreFromXml(in); 1012 } else if (TAG_INTENT.equals(name)) { 1013 intent = Intent.restoreFromXml(in); 1014 } else if (TAG_ACTIVITY.equals(name)) { 1015 ActivityRecord activity = 1016 ActivityRecord.restoreFromXml(in, taskId, stackSupervisor); 1017 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + 1018 activity); 1019 if (activity != null) { 1020 activities.add(activity); 1021 } 1022 } else { 1023 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 1024 XmlUtils.skipCurrentTag(in); 1025 } 1026 } 1027 } 1028 1029 if (lastActiveTime >= 0) { 1030 taskDescription.setIcon(TaskPersister.restoreImage( 1031 createLastTaskDescriptionIconFilename(taskId, lastActiveTime))); 1032 } 1033 1034 if (!hasRootAffinity) { 1035 rootAffinity = affinity; 1036 } else if ("@".equals(rootAffinity)) { 1037 rootAffinity = null; 1038 } 1039 1040 if (effectiveUid <= 0) { 1041 Intent checkIntent = intent != null ? intent : affinityIntent; 1042 effectiveUid = 0; 1043 if (checkIntent != null) { 1044 IPackageManager pm = AppGlobals.getPackageManager(); 1045 try { 1046 ApplicationInfo ai = pm.getApplicationInfo( 1047 checkIntent.getComponent().getPackageName(), 1048 PackageManager.GET_UNINSTALLED_PACKAGES 1049 | PackageManager.GET_DISABLED_COMPONENTS, userId); 1050 if (ai != null) { 1051 effectiveUid = ai.uid; 1052 } 1053 } catch (RemoteException e) { 1054 } 1055 } 1056 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 1057 + ": effectiveUid=" + effectiveUid); 1058 } 1059 1060 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, 1061 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, 1062 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription, 1063 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, 1064 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, 1065 callingUid, callingPackage); 1066 1067 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { 1068 activities.get(activityNdx).task = task; 1069 } 1070 1071 if (ActivityManagerService.DEBUG_RECENTS) Slog.d(TAG, "Restored task=" + task); 1072 return task; 1073 } 1074 1075 void dump(PrintWriter pw, String prefix) { 1076 pw.print(prefix); pw.print("userId="); pw.print(userId); 1077 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 1078 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 1079 pw.print(" mCallingPackage="); pw.println(mCallingPackage); 1080 if (affinity != null || rootAffinity != null) { 1081 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 1082 if (affinity == null || !affinity.equals(rootAffinity)) { 1083 pw.print(" root="); pw.println(rootAffinity); 1084 } else { 1085 pw.println(); 1086 } 1087 } 1088 if (voiceSession != null || voiceInteractor != null) { 1089 pw.print(prefix); pw.print("VOICE: session=0x"); 1090 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 1091 pw.print(" interactor=0x"); 1092 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 1093 } 1094 if (intent != null) { 1095 StringBuilder sb = new StringBuilder(128); 1096 sb.append(prefix); sb.append("intent={"); 1097 intent.toShortString(sb, false, true, false, true); 1098 sb.append('}'); 1099 pw.println(sb.toString()); 1100 } 1101 if (affinityIntent != null) { 1102 StringBuilder sb = new StringBuilder(128); 1103 sb.append(prefix); sb.append("affinityIntent={"); 1104 affinityIntent.toShortString(sb, false, true, false, true); 1105 sb.append('}'); 1106 pw.println(sb.toString()); 1107 } 1108 if (origActivity != null) { 1109 pw.print(prefix); pw.print("origActivity="); 1110 pw.println(origActivity.flattenToShortString()); 1111 } 1112 if (realActivity != null) { 1113 pw.print(prefix); pw.print("realActivity="); 1114 pw.println(realActivity.flattenToShortString()); 1115 } 1116 if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0 1117 || numFullscreen != 0) { 1118 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 1119 pw.print(" isPersistable="); pw.print(isPersistable); 1120 pw.print(" numFullscreen="); pw.print(numFullscreen); 1121 pw.print(" taskType="); pw.print(taskType); 1122 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo); 1123 } 1124 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask) { 1125 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 1126 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 1127 pw.print(" mReuseTask="); pw.println(mReuseTask); 1128 } 1129 if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != -1 || mPrevAffiliate != null 1130 || mNextAffiliateTaskId != -1 || mNextAffiliate != null) { 1131 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 1132 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 1133 pw.print(" ("); 1134 if (mPrevAffiliate == null) { 1135 pw.print("null"); 1136 } else { 1137 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 1138 } 1139 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 1140 pw.print(" ("); 1141 if (mNextAffiliate == null) { 1142 pw.print("null"); 1143 } else { 1144 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 1145 } 1146 pw.println(")"); 1147 } 1148 pw.print(prefix); pw.print("Activities="); pw.println(mActivities); 1149 if (!askedCompatMode || !inRecents || !isAvailable) { 1150 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 1151 pw.print(" inRecents="); pw.print(inRecents); 1152 pw.print(" isAvailable="); pw.println(isAvailable); 1153 } 1154 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail); 1155 pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile); 1156 if (lastDescription != null) { 1157 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 1158 } 1159 pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible); 1160 pw.print(" firstActiveTime="); pw.print(lastActiveTime); 1161 pw.print(" lastActiveTime="); pw.print(lastActiveTime); 1162 pw.print(" (inactive for "); 1163 pw.print((getInactiveDuration()/1000)); pw.println("s)"); 1164 } 1165 1166 @Override 1167 public String toString() { 1168 StringBuilder sb = new StringBuilder(128); 1169 if (stringName != null) { 1170 sb.append(stringName); 1171 sb.append(" U="); 1172 sb.append(userId); 1173 sb.append(" sz="); 1174 sb.append(mActivities.size()); 1175 sb.append('}'); 1176 return sb.toString(); 1177 } 1178 sb.append("TaskRecord{"); 1179 sb.append(Integer.toHexString(System.identityHashCode(this))); 1180 sb.append(" #"); 1181 sb.append(taskId); 1182 if (affinity != null) { 1183 sb.append(" A="); 1184 sb.append(affinity); 1185 } else if (intent != null) { 1186 sb.append(" I="); 1187 sb.append(intent.getComponent().flattenToShortString()); 1188 } else if (affinityIntent != null) { 1189 sb.append(" aI="); 1190 sb.append(affinityIntent.getComponent().flattenToShortString()); 1191 } else { 1192 sb.append(" ??"); 1193 } 1194 stringName = sb.toString(); 1195 return toString(); 1196 } 1197} 1198