ActivityRecord.java revision 43e52ed32e2d55ef4aee18c4b4bc13b7fdef9cc4
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import android.app.ActivityManager.TaskDescription;
20import android.os.PersistableBundle;
21import android.os.Trace;
22import com.android.internal.app.ResolverActivity;
23import com.android.internal.util.XmlUtils;
24import com.android.server.AttributeCache;
25import com.android.server.am.ActivityStack.ActivityState;
26import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
27
28import android.app.ActivityOptions;
29import android.app.ResultInfo;
30import android.content.ComponentName;
31import android.content.Intent;
32import android.content.pm.ActivityInfo;
33import android.content.pm.ApplicationInfo;
34import android.content.res.CompatibilityInfo;
35import android.content.res.Configuration;
36import android.graphics.Bitmap;
37import android.graphics.Rect;
38import android.os.Build;
39import android.os.Bundle;
40import android.os.IBinder;
41import android.os.Message;
42import android.os.Process;
43import android.os.RemoteException;
44import android.os.SystemClock;
45import android.os.UserHandle;
46import android.util.EventLog;
47import android.util.Log;
48import android.util.Slog;
49import android.util.TimeUtils;
50import android.view.IApplicationToken;
51import android.view.WindowManager;
52import org.xmlpull.v1.XmlPullParser;
53import org.xmlpull.v1.XmlPullParserException;
54import org.xmlpull.v1.XmlSerializer;
55
56import java.io.IOException;
57import java.io.PrintWriter;
58import java.lang.ref.WeakReference;
59import java.util.ArrayList;
60import java.util.HashSet;
61
62/**
63 * An entry in the history stack, representing an activity.
64 */
65final class ActivityRecord {
66    static final String TAG = ActivityManagerService.TAG;
67    static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
68    final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recent";
69
70    private static final String TAG_ACTIVITY = "activity";
71    private static final String ATTR_ID = "id";
72    private static final String TAG_INTENT = "intent";
73    private static final String ATTR_USERID = "user_id";
74    private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle";
75    private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid";
76    private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
77    private static final String ATTR_RESOLVEDTYPE = "resolved_type";
78    private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
79    private static final String ATTR_TASKDESCRIPTIONLABEL = "task_description_label";
80    private static final String ATTR_TASKDESCRIPTIONCOLOR = "task_description_color";
81    private static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
82
83    final ActivityManagerService service; // owner
84    final IApplicationToken.Stub appToken; // window manager token
85    final ActivityInfo info; // all about me
86    final int launchedFromUid; // always the uid who started the activity.
87    final String launchedFromPackage; // always the package who started the activity.
88    final int userId;          // Which user is this running for?
89    final Intent intent;    // the original intent that generated us
90    final ComponentName realActivity;  // the intent component, or target of an alias.
91    final String shortComponentName; // the short component name of the intent
92    final String resolvedType; // as per original caller;
93    final String packageName; // the package implementing intent's component
94    final String processName; // process where this component wants to run
95    final String taskAffinity; // as per ActivityInfo.taskAffinity
96    final boolean stateNotNeeded; // As per ActivityInfo.flags
97    boolean fullscreen; // covers the full screen?
98    final boolean noDisplay;  // activity is not displayed?
99    final boolean componentSpecified;  // did caller specifiy an explicit component?
100
101    static final int APPLICATION_ACTIVITY_TYPE = 0;
102    static final int HOME_ACTIVITY_TYPE = 1;
103    static final int RECENTS_ACTIVITY_TYPE = 2;
104    int mActivityType;
105
106    final String baseDir;   // where activity source (resources etc) located
107    final String resDir;   // where public activity source (public resources etc) located
108    final String dataDir;   // where activity data should go
109    CharSequence nonLocalizedLabel;  // the label information from the package mgr.
110    int labelRes;           // the label information from the package mgr.
111    int icon;               // resource identifier of activity's icon.
112    int logo;               // resource identifier of activity's logo.
113    int theme;              // resource identifier of activity's theme.
114    int realTheme;          // actual theme resource we will use, never 0.
115    int windowFlags;        // custom window flags for preview window.
116    TaskRecord task;        // the task this is in.
117    ThumbnailHolder thumbHolder; // where our thumbnails should go.
118    long createTime = System.currentTimeMillis();
119    long displayStartTime;  // when we started launching this activity
120    long fullyDrawnStartTime; // when we started launching this activity
121    long startTime;         // last time this activity was started
122    long lastVisibleTime;   // last time this activity became visible
123    long cpuTimeAtResume;   // the cpu time of host process at the time of resuming activity
124    long pauseTime;         // last time we started pausing the activity
125    long launchTickTime;    // base time for launch tick messages
126    Configuration configuration; // configuration activity was last running in
127    CompatibilityInfo compat;// last used compatibility mode
128    ActivityRecord resultTo; // who started this entry, so will get our reply
129    final String resultWho; // additional identifier for use by resultTo.
130    final int requestCode;  // code given by requester (resultTo)
131    ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
132    HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
133    ArrayList<Intent> newIntents; // any pending new intents for single-top mode
134    ActivityOptions pendingOptions; // most recently given options
135    HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
136    UriPermissionOwner uriPermissions; // current special URI access perms.
137    ProcessRecord app;      // if non-null, hosting application
138    ActivityState state;    // current state we are in
139    Bundle  icicle;         // last saved activity state
140    PersistableBundle persistentState; // last persistently saved activity state
141    boolean frontOfTask;    // is this the root activity of its task?
142    boolean launchFailed;   // set if a launched failed, to abort on 2nd try
143    boolean haveState;      // have we gotten the last activity state?
144    boolean stopped;        // is activity pause finished?
145    boolean delayedResume;  // not yet resumed because of stopped app switches?
146    boolean finishing;      // activity in pending finish list?
147    boolean configDestroy;  // need to destroy due to config change?
148    int configChangeFlags;  // which config values have changed
149    boolean keysPaused;     // has key dispatching been paused for it?
150    int launchMode;         // the launch mode activity attribute.
151    boolean visible;        // does this activity's window need to be shown?
152    boolean sleeping;       // have we told the activity to sleep?
153    boolean waitingVisible; // true if waiting for a new act to become vis
154    boolean nowVisible;     // is this activity's window visible?
155    boolean idle;           // has the activity gone idle?
156    boolean hasBeenLaunched;// has this activity ever been launched?
157    boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
158    boolean immersive;      // immersive mode (don't interrupt if possible)
159    boolean forceNewConfig; // force re-create with new config next time
160    int launchCount;        // count of launches since last state
161    long lastLaunchTime;    // time of last lauch of this activity
162    ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>();
163
164    String stringName;      // for caching of toString().
165
166    private boolean inHistory;  // are we in the history stack?
167    final ActivityStackSupervisor mStackSupervisor;
168    boolean mStartingWindowShown = false;
169    ActivityContainer mInitialActivityContainer;
170
171    TaskDescription taskDescription; // the recents information for this activity
172
173    void dump(PrintWriter pw, String prefix) {
174        final long now = SystemClock.uptimeMillis();
175        pw.print(prefix); pw.print("packageName="); pw.print(packageName);
176                pw.print(" processName="); pw.println(processName);
177        pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
178                pw.print(" launchedFromPackage="); pw.print(launchedFromPackage);
179                pw.print(" userId="); pw.println(userId);
180        pw.print(prefix); pw.print("app="); pw.println(app);
181        pw.print(prefix); pw.println(intent.toInsecureStringWithClip());
182        pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask);
183                pw.print(" task="); pw.println(task);
184        pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
185        pw.print(prefix); pw.print("realActivity=");
186                pw.println(realActivity.flattenToShortString());
187        pw.print(prefix); pw.print("baseDir="); pw.println(baseDir);
188        if (!resDir.equals(baseDir)) {
189            pw.print(prefix); pw.print("resDir="); pw.println(resDir);
190        }
191        pw.print(prefix); pw.print("dataDir="); pw.println(dataDir);
192        pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
193                pw.print(" componentSpecified="); pw.print(componentSpecified);
194                pw.print(" mActivityType="); pw.println(mActivityType);
195        pw.print(prefix); pw.print("compat="); pw.print(compat);
196                pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes));
197                pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
198                pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
199        pw.print(prefix); pw.print("config="); pw.println(configuration);
200        if (resultTo != null || resultWho != null) {
201            pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
202                    pw.print(" resultWho="); pw.print(resultWho);
203                    pw.print(" resultCode="); pw.println(requestCode);
204        }
205        if (results != null) {
206            pw.print(prefix); pw.print("results="); pw.println(results);
207        }
208        if (pendingResults != null && pendingResults.size() > 0) {
209            pw.print(prefix); pw.println("Pending Results:");
210            for (WeakReference<PendingIntentRecord> wpir : pendingResults) {
211                PendingIntentRecord pir = wpir != null ? wpir.get() : null;
212                pw.print(prefix); pw.print("  - ");
213                if (pir == null) {
214                    pw.println("null");
215                } else {
216                    pw.println(pir);
217                    pir.dump(pw, prefix + "    ");
218                }
219            }
220        }
221        if (newIntents != null && newIntents.size() > 0) {
222            pw.print(prefix); pw.println("Pending New Intents:");
223            for (int i=0; i<newIntents.size(); i++) {
224                Intent intent = newIntents.get(i);
225                pw.print(prefix); pw.print("  - ");
226                if (intent == null) {
227                    pw.println("null");
228                } else {
229                    pw.println(intent.toShortString(false, true, false, true));
230                }
231            }
232        }
233        if (pendingOptions != null) {
234            pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions);
235        }
236        if (uriPermissions != null) {
237            uriPermissions.dump(pw, prefix);
238        }
239        pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed);
240                pw.print(" launchCount="); pw.print(launchCount);
241                pw.print(" lastLaunchTime=");
242                if (lastLaunchTime == 0) pw.print("0");
243                else TimeUtils.formatDuration(lastLaunchTime, now, pw);
244                pw.println();
245        pw.print(prefix); pw.print("haveState="); pw.print(haveState);
246                pw.print(" icicle="); pw.println(icicle);
247        pw.print(prefix); pw.print("state="); pw.print(state);
248                pw.print(" stopped="); pw.print(stopped);
249                pw.print(" delayedResume="); pw.print(delayedResume);
250                pw.print(" finishing="); pw.println(finishing);
251        pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
252                pw.print(" inHistory="); pw.print(inHistory);
253                pw.print(" visible="); pw.print(visible);
254                pw.print(" sleeping="); pw.print(sleeping);
255                pw.print(" idle="); pw.println(idle);
256        pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
257                pw.print(" noDisplay="); pw.print(noDisplay);
258                pw.print(" immersive="); pw.print(immersive);
259                pw.print(" launchMode="); pw.println(launchMode);
260        pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
261                pw.print(" forceNewConfig="); pw.println(forceNewConfig);
262        pw.print(prefix); pw.print("mActivityType=");
263                pw.println(activityTypeToString(mActivityType));
264        pw.print(prefix); pw.print("thumbHolder: ");
265                pw.print(Integer.toHexString(System.identityHashCode(thumbHolder)));
266                if (thumbHolder != null) {
267                    pw.print(" bm="); pw.print(thumbHolder.lastThumbnail);
268                    pw.print(" desc="); pw.print(thumbHolder.lastDescription);
269                }
270                pw.println();
271        if (displayStartTime != 0 || startTime != 0) {
272            pw.print(prefix); pw.print("displayStartTime=");
273                    if (displayStartTime == 0) pw.print("0");
274                    else TimeUtils.formatDuration(displayStartTime, now, pw);
275                    pw.print(" startTime=");
276                    if (startTime == 0) pw.print("0");
277                    else TimeUtils.formatDuration(startTime, now, pw);
278                    pw.println();
279        }
280        if (lastVisibleTime != 0 || waitingVisible || nowVisible) {
281            pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
282                    pw.print(" nowVisible="); pw.print(nowVisible);
283                    pw.print(" lastVisibleTime=");
284                    if (lastVisibleTime == 0) pw.print("0");
285                    else TimeUtils.formatDuration(lastVisibleTime, now, pw);
286                    pw.println();
287        }
288        if (configDestroy || configChangeFlags != 0) {
289            pw.print(prefix); pw.print("configDestroy="); pw.print(configDestroy);
290                    pw.print(" configChangeFlags=");
291                    pw.println(Integer.toHexString(configChangeFlags));
292        }
293        if (connections != null) {
294            pw.print(prefix); pw.print("connections="); pw.println(connections);
295        }
296    }
297
298    static class Token extends IApplicationToken.Stub {
299        final WeakReference<ActivityRecord> weakActivity;
300
301        Token(ActivityRecord activity) {
302            weakActivity = new WeakReference<ActivityRecord>(activity);
303        }
304
305        @Override public void windowsDrawn() {
306            ActivityRecord activity = weakActivity.get();
307            if (activity != null) {
308                activity.windowsDrawn();
309            }
310        }
311
312        @Override public void windowsVisible() {
313            ActivityRecord activity = weakActivity.get();
314            if (activity != null) {
315                activity.windowsVisible();
316            }
317        }
318
319        @Override public void windowsGone() {
320            ActivityRecord activity = weakActivity.get();
321            if (activity != null) {
322                activity.windowsGone();
323            }
324        }
325
326        @Override public boolean keyDispatchingTimedOut(String reason) {
327            ActivityRecord activity = weakActivity.get();
328            return activity != null && activity.keyDispatchingTimedOut(reason);
329        }
330
331        @Override public long getKeyDispatchingTimeout() {
332            ActivityRecord activity = weakActivity.get();
333            if (activity != null) {
334                return activity.getKeyDispatchingTimeout();
335            }
336            return 0;
337        }
338
339        @Override
340        public String toString() {
341            StringBuilder sb = new StringBuilder(128);
342            sb.append("Token{");
343            sb.append(Integer.toHexString(System.identityHashCode(this)));
344            sb.append(' ');
345            sb.append(weakActivity.get());
346            sb.append('}');
347            return sb.toString();
348        }
349    }
350
351    static ActivityRecord forToken(IBinder token) {
352        try {
353            return token != null ? ((Token)token).weakActivity.get() : null;
354        } catch (ClassCastException e) {
355            Slog.w(ActivityManagerService.TAG, "Bad activity token: " + token, e);
356            return null;
357        }
358    }
359
360    boolean isNotResolverActivity() {
361        return !ResolverActivity.class.getName().equals(realActivity.getClassName());
362    }
363
364    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
365            int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
366            ActivityInfo aInfo, Configuration _configuration,
367            ActivityRecord _resultTo, String _resultWho, int _reqCode,
368            boolean _componentSpecified, ActivityStackSupervisor supervisor,
369            ActivityContainer container, Bundle options) {
370        service = _service;
371        appToken = new Token(this);
372        info = aInfo;
373        launchedFromUid = _launchedFromUid;
374        launchedFromPackage = _launchedFromPackage;
375        userId = UserHandle.getUserId(aInfo.applicationInfo.uid);
376        intent = _intent;
377        shortComponentName = _intent.getComponent().flattenToShortString();
378        resolvedType = _resolvedType;
379        componentSpecified = _componentSpecified;
380        configuration = _configuration;
381        resultTo = _resultTo;
382        resultWho = _resultWho;
383        requestCode = _reqCode;
384        state = ActivityState.INITIALIZING;
385        frontOfTask = false;
386        launchFailed = false;
387        stopped = false;
388        delayedResume = false;
389        finishing = false;
390        configDestroy = false;
391        keysPaused = false;
392        inHistory = false;
393        visible = true;
394        waitingVisible = false;
395        nowVisible = false;
396        idle = false;
397        hasBeenLaunched = false;
398        mStackSupervisor = supervisor;
399        mInitialActivityContainer = container;
400        if (options != null) {
401            pendingOptions = new ActivityOptions(options);
402        }
403
404        // This starts out true, since the initial state of an activity
405        // is that we have everything, and we shouldn't never consider it
406        // lacking in state to be removed if it dies.
407        haveState = true;
408
409        if (aInfo != null) {
410            if (aInfo.targetActivity == null
411                    || aInfo.launchMode == ActivityInfo.LAUNCH_MULTIPLE
412                    || aInfo.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
413                realActivity = _intent.getComponent();
414            } else {
415                realActivity = new ComponentName(aInfo.packageName,
416                        aInfo.targetActivity);
417            }
418            taskAffinity = aInfo.taskAffinity;
419            stateNotNeeded = (aInfo.flags&
420                    ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0;
421            baseDir = aInfo.applicationInfo.sourceDir;
422            resDir = aInfo.applicationInfo.publicSourceDir;
423            dataDir = aInfo.applicationInfo.dataDir;
424            nonLocalizedLabel = aInfo.nonLocalizedLabel;
425            labelRes = aInfo.labelRes;
426            if (nonLocalizedLabel == null && labelRes == 0) {
427                ApplicationInfo app = aInfo.applicationInfo;
428                nonLocalizedLabel = app.nonLocalizedLabel;
429                labelRes = app.labelRes;
430            }
431            icon = aInfo.getIconResource();
432            logo = aInfo.getLogoResource();
433            theme = aInfo.getThemeResource();
434            realTheme = theme;
435            if (realTheme == 0) {
436                realTheme = aInfo.applicationInfo.targetSdkVersion
437                        < Build.VERSION_CODES.HONEYCOMB
438                        ? android.R.style.Theme
439                        : android.R.style.Theme_Holo;
440            }
441            if ((aInfo.flags&ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
442                windowFlags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
443            }
444            if ((aInfo.flags&ActivityInfo.FLAG_MULTIPROCESS) != 0
445                    && _caller != null
446                    && (aInfo.applicationInfo.uid == Process.SYSTEM_UID
447                            || aInfo.applicationInfo.uid == _caller.info.uid)) {
448                processName = _caller.processName;
449            } else {
450                processName = aInfo.processName;
451            }
452
453            if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
454                intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
455            }
456
457            packageName = aInfo.applicationInfo.packageName;
458            launchMode = aInfo.launchMode;
459
460            AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
461                    realTheme, com.android.internal.R.styleable.Window, userId);
462            fullscreen = ent != null && !ent.array.getBoolean(
463                    com.android.internal.R.styleable.Window_windowIsFloating, false)
464                    && !ent.array.getBoolean(
465                    com.android.internal.R.styleable.Window_windowIsTranslucent, false);
466            noDisplay = ent != null && ent.array.getBoolean(
467                    com.android.internal.R.styleable.Window_windowNoDisplay, false);
468
469            if ((!_componentSpecified || _launchedFromUid == Process.myUid()
470                    || _launchedFromUid == 0) &&
471                    Intent.ACTION_MAIN.equals(_intent.getAction()) &&
472                    _intent.hasCategory(Intent.CATEGORY_HOME) &&
473                    _intent.getCategories().size() == 1 &&
474                    _intent.getData() == null &&
475                    _intent.getType() == null &&
476                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
477                    isNotResolverActivity()) {
478                // This sure looks like a home activity!
479                mActivityType = HOME_ACTIVITY_TYPE;
480            } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
481                mActivityType = RECENTS_ACTIVITY_TYPE;
482            } else {
483                mActivityType = APPLICATION_ACTIVITY_TYPE;
484            }
485
486            immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
487        } else {
488            realActivity = null;
489            taskAffinity = null;
490            stateNotNeeded = false;
491            baseDir = null;
492            resDir = null;
493            dataDir = null;
494            processName = null;
495            packageName = null;
496            fullscreen = true;
497            noDisplay = false;
498            mActivityType = APPLICATION_ACTIVITY_TYPE;
499            immersive = false;
500        }
501    }
502
503    void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
504        if (task != null && task.removeActivity(this)) {
505            if (task != newTask) {
506                task.stack.removeTask(task);
507            } else {
508                Slog.d(TAG, "!!! REMOVE THIS LOG !!! setTask: nearly removed stack=" +
509                        (newTask == null ? null : newTask.stack));
510            }
511        }
512        if (newThumbHolder == null) {
513            newThumbHolder = newTask;
514        }
515        task = newTask;
516        if (!isRoot && (intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
517            // This is the start of a new sub-task.
518            if (thumbHolder == null) {
519                thumbHolder = new ThumbnailHolder();
520            }
521        } else {
522            thumbHolder = newThumbHolder;
523        }
524    }
525
526    boolean changeWindowTranslucency(boolean toOpaque) {
527        if (fullscreen == toOpaque) {
528            return false;
529        }
530
531        // Keep track of the number of fullscreen activities in this task.
532        task.numFullscreen += toOpaque ? +1 : -1;
533
534        fullscreen = toOpaque;
535        return true;
536    }
537
538    void putInHistory() {
539        if (!inHistory) {
540            inHistory = true;
541        }
542    }
543
544    void takeFromHistory() {
545        if (inHistory) {
546            inHistory = false;
547            if (task != null && !finishing) {
548                task = null;
549            }
550            clearOptionsLocked();
551        }
552    }
553
554    boolean isInHistory() {
555        return inHistory;
556    }
557
558    boolean isHomeActivity() {
559        return mActivityType == HOME_ACTIVITY_TYPE;
560    }
561
562    boolean isRecentsActivity() {
563        return mActivityType == RECENTS_ACTIVITY_TYPE;
564    }
565
566    boolean isApplicationActivity() {
567        return mActivityType == APPLICATION_ACTIVITY_TYPE;
568    }
569
570    boolean isPersistable() {
571        return (info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY ||
572                info.persistableMode == ActivityInfo.PERSIST_ACROSS_REBOOTS) &&
573                (intent == null ||
574                        (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
575    }
576
577    void makeFinishing() {
578        if (!finishing) {
579            finishing = true;
580            if (stopped) {
581                clearOptionsLocked();
582            }
583        }
584    }
585
586    boolean isRootActivity() {
587        final ArrayList<ActivityRecord> activities = task.mActivities;
588        return activities.size() == 0 || this == activities.get(0);
589    }
590
591    UriPermissionOwner getUriPermissionsLocked() {
592        if (uriPermissions == null) {
593            uriPermissions = new UriPermissionOwner(service, this);
594        }
595        return uriPermissions;
596    }
597
598    void addResultLocked(ActivityRecord from, String resultWho,
599            int requestCode, int resultCode,
600            Intent resultData) {
601        ActivityResult r = new ActivityResult(from, resultWho,
602                requestCode, resultCode, resultData);
603        if (results == null) {
604            results = new ArrayList<ResultInfo>();
605        }
606        results.add(r);
607    }
608
609    void removeResultsLocked(ActivityRecord from, String resultWho,
610            int requestCode) {
611        if (results != null) {
612            for (int i=results.size()-1; i>=0; i--) {
613                ActivityResult r = (ActivityResult)results.get(i);
614                if (r.mFrom != from) continue;
615                if (r.mResultWho == null) {
616                    if (resultWho != null) continue;
617                } else {
618                    if (!r.mResultWho.equals(resultWho)) continue;
619                }
620                if (r.mRequestCode != requestCode) continue;
621
622                results.remove(i);
623            }
624        }
625    }
626
627    void addNewIntentLocked(Intent intent) {
628        if (newIntents == null) {
629            newIntents = new ArrayList<Intent>();
630        }
631        newIntents.add(intent);
632    }
633
634    /**
635     * Deliver a new Intent to an existing activity, so that its onNewIntent()
636     * method will be called at the proper time.
637     */
638    final void deliverNewIntentLocked(int callingUid, Intent intent) {
639        // The activity now gets access to the data associated with this Intent.
640        service.grantUriPermissionFromIntentLocked(callingUid, packageName,
641                intent, getUriPermissionsLocked(), userId);
642        // We want to immediately deliver the intent to the activity if
643        // it is currently the top resumed activity...  however, if the
644        // device is sleeping, then all activities are stopped, so in that
645        // case we will deliver it if this is the current top activity on its
646        // stack.
647        boolean unsent = true;
648        if ((state == ActivityState.RESUMED || (service.isSleeping()
649                        && task.stack.topRunningActivityLocked(null) == this))
650                && app != null && app.thread != null) {
651            try {
652                ArrayList<Intent> ar = new ArrayList<Intent>();
653                intent = new Intent(intent);
654                ar.add(intent);
655                app.thread.scheduleNewIntent(ar, appToken);
656                unsent = false;
657            } catch (RemoteException e) {
658                Slog.w(ActivityManagerService.TAG,
659                        "Exception thrown sending new intent to " + this, e);
660            } catch (NullPointerException e) {
661                Slog.w(ActivityManagerService.TAG,
662                        "Exception thrown sending new intent to " + this, e);
663            }
664        }
665        if (unsent) {
666            addNewIntentLocked(new Intent(intent));
667        }
668    }
669
670    void updateOptionsLocked(Bundle options) {
671        if (options != null) {
672            if (pendingOptions != null) {
673                pendingOptions.abort();
674            }
675            pendingOptions = new ActivityOptions(options);
676        }
677    }
678
679    void updateOptionsLocked(ActivityOptions options) {
680        if (options != null) {
681            if (pendingOptions != null) {
682                pendingOptions.abort();
683            }
684            pendingOptions = options;
685        }
686    }
687
688    void applyOptionsLocked() {
689        if (pendingOptions != null
690                && pendingOptions.getAnimationType() != ActivityOptions.ANIM_SCENE_TRANSITION) {
691            final int animationType = pendingOptions.getAnimationType();
692            switch (animationType) {
693                case ActivityOptions.ANIM_CUSTOM:
694                    service.mWindowManager.overridePendingAppTransition(
695                            pendingOptions.getPackageName(),
696                            pendingOptions.getCustomEnterResId(),
697                            pendingOptions.getCustomExitResId(),
698                            pendingOptions.getOnAnimationStartListener());
699                    break;
700                case ActivityOptions.ANIM_SCALE_UP:
701                    service.mWindowManager.overridePendingAppTransitionScaleUp(
702                            pendingOptions.getStartX(), pendingOptions.getStartY(),
703                            pendingOptions.getStartWidth(), pendingOptions.getStartHeight());
704                    if (intent.getSourceBounds() == null) {
705                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
706                                pendingOptions.getStartY(),
707                                pendingOptions.getStartX()+pendingOptions.getStartWidth(),
708                                pendingOptions.getStartY()+pendingOptions.getStartHeight()));
709                    }
710                    break;
711                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
712                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
713                    boolean scaleUp = (animationType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
714                    service.mWindowManager.overridePendingAppTransitionThumb(
715                            pendingOptions.getThumbnail(),
716                            pendingOptions.getStartX(), pendingOptions.getStartY(),
717                            pendingOptions.getOnAnimationStartListener(),
718                            scaleUp);
719                    if (intent.getSourceBounds() == null) {
720                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
721                                pendingOptions.getStartY(),
722                                pendingOptions.getStartX()
723                                        + pendingOptions.getThumbnail().getWidth(),
724                                pendingOptions.getStartY()
725                                        + pendingOptions.getThumbnail().getHeight()));
726                    }
727                    break;
728                default:
729                    Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
730                    break;
731            }
732            pendingOptions = null;
733        }
734    }
735
736    ActivityOptions getOptionsForTargetActivityLocked() {
737        return pendingOptions != null ? pendingOptions.forTargetActivity() : null;
738    }
739
740    void clearOptionsLocked() {
741        if (pendingOptions != null) {
742            pendingOptions.abort();
743            pendingOptions = null;
744        }
745    }
746
747    ActivityOptions takeOptionsLocked() {
748        ActivityOptions opts = pendingOptions;
749        pendingOptions = null;
750        return opts;
751    }
752
753    void removeUriPermissionsLocked() {
754        if (uriPermissions != null) {
755            uriPermissions.removeUriPermissionsLocked();
756            uriPermissions = null;
757        }
758    }
759
760    void pauseKeyDispatchingLocked() {
761        if (!keysPaused) {
762            keysPaused = true;
763            service.mWindowManager.pauseKeyDispatching(appToken);
764        }
765    }
766
767    void resumeKeyDispatchingLocked() {
768        if (keysPaused) {
769            keysPaused = false;
770            service.mWindowManager.resumeKeyDispatching(appToken);
771        }
772    }
773
774    void updateThumbnail(Bitmap newThumbnail, CharSequence description) {
775        if (thumbHolder != null) {
776            if (newThumbnail != null) {
777                if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
778                        "Setting thumbnail of " + this + " holder " + thumbHolder
779                        + " to " + newThumbnail);
780                thumbHolder.lastThumbnail = newThumbnail;
781                if (isPersistable()) {
782                    mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
783                }
784            }
785            thumbHolder.lastDescription = description;
786        }
787    }
788
789    void startLaunchTickingLocked() {
790        if (ActivityManagerService.IS_USER_BUILD) {
791            return;
792        }
793        if (launchTickTime == 0) {
794            launchTickTime = SystemClock.uptimeMillis();
795            continueLaunchTickingLocked();
796        }
797    }
798
799    boolean continueLaunchTickingLocked() {
800        if (launchTickTime != 0) {
801            final ActivityStack stack = task.stack;
802            Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG, this);
803            stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
804            stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK);
805            return true;
806        }
807        return false;
808    }
809
810    void finishLaunchTickingLocked() {
811        launchTickTime = 0;
812        task.stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
813    }
814
815    // IApplicationToken
816
817    public boolean mayFreezeScreenLocked(ProcessRecord app) {
818        // Only freeze the screen if this activity is currently attached to
819        // an application, and that application is not blocked or unresponding.
820        // In any other case, we can't count on getting the screen unfrozen,
821        // so it is best to leave as-is.
822        return app != null && !app.crashing && !app.notResponding;
823    }
824
825    public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
826        if (mayFreezeScreenLocked(app)) {
827            service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
828        }
829    }
830
831    public void stopFreezingScreenLocked(boolean force) {
832        if (force || frozenBeforeDestroy) {
833            frozenBeforeDestroy = false;
834            service.mWindowManager.stopAppFreezingScreen(appToken, force);
835        }
836    }
837
838    public void reportFullyDrawnLocked() {
839        final long curTime = SystemClock.uptimeMillis();
840        if (displayStartTime != 0) {
841            reportLaunchTimeLocked(curTime);
842        }
843        if (fullyDrawnStartTime != 0) {
844            final ActivityStack stack = task.stack;
845            final long thisTime = curTime - fullyDrawnStartTime;
846            final long totalTime = stack.mFullyDrawnStartTime != 0
847                    ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
848            if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
849                Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
850                EventLog.writeEvent(EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME,
851                        userId, System.identityHashCode(this), shortComponentName,
852                        thisTime, totalTime);
853                StringBuilder sb = service.mStringBuilder;
854                sb.setLength(0);
855                sb.append("Fully drawn ");
856                sb.append(shortComponentName);
857                sb.append(": ");
858                TimeUtils.formatDuration(thisTime, sb);
859                if (thisTime != totalTime) {
860                    sb.append(" (total ");
861                    TimeUtils.formatDuration(totalTime, sb);
862                    sb.append(")");
863                }
864                Log.i(ActivityManagerService.TAG, sb.toString());
865            }
866            if (totalTime > 0) {
867                service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime);
868            }
869            fullyDrawnStartTime = 0;
870            stack.mFullyDrawnStartTime = 0;
871        }
872    }
873
874    private void reportLaunchTimeLocked(final long curTime) {
875        final ActivityStack stack = task.stack;
876        final long thisTime = curTime - displayStartTime;
877        final long totalTime = stack.mLaunchStartTime != 0
878                ? (curTime - stack.mLaunchStartTime) : thisTime;
879        if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
880            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
881            EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
882                    userId, System.identityHashCode(this), shortComponentName,
883                    thisTime, totalTime);
884            StringBuilder sb = service.mStringBuilder;
885            sb.setLength(0);
886            sb.append("Displayed ");
887            sb.append(shortComponentName);
888            sb.append(": ");
889            TimeUtils.formatDuration(thisTime, sb);
890            if (thisTime != totalTime) {
891                sb.append(" (total ");
892                TimeUtils.formatDuration(totalTime, sb);
893                sb.append(")");
894            }
895            Log.i(ActivityManagerService.TAG, sb.toString());
896        }
897        mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
898        if (totalTime > 0) {
899            service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
900        }
901        displayStartTime = 0;
902        stack.mLaunchStartTime = 0;
903    }
904
905    public void windowsDrawn() {
906        synchronized(service) {
907            if (displayStartTime != 0) {
908                reportLaunchTimeLocked(SystemClock.uptimeMillis());
909            }
910            startTime = 0;
911            finishLaunchTickingLocked();
912            if (task != null) {
913                task.hasBeenVisible = true;
914            }
915        }
916    }
917
918    public void windowsVisible() {
919        synchronized(service) {
920            mStackSupervisor.reportActivityVisibleLocked(this);
921            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
922                    ActivityManagerService.TAG, "windowsVisible(): " + this);
923            if (!nowVisible) {
924                nowVisible = true;
925                lastVisibleTime = SystemClock.uptimeMillis();
926                if (!idle) {
927                    // Instead of doing the full stop routine here, let's just
928                    // hide any activities we now can, and let them stop when
929                    // the normal idle happens.
930                    mStackSupervisor.processStoppingActivitiesLocked(false);
931                } else {
932                    // If this activity was already idle, then we now need to
933                    // make sure we perform the full stop of any activities
934                    // that are waiting to do so.  This is because we won't
935                    // do that while they are still waiting for this one to
936                    // become visible.
937                    final int N = mStackSupervisor.mWaitingVisibleActivities.size();
938                    if (N > 0) {
939                        for (int i=0; i<N; i++) {
940                            ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
941                            r.waitingVisible = false;
942                            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
943                                    ActivityManagerService.TAG,
944                                    "Was waiting for visible: " + r);
945                        }
946                        mStackSupervisor.mWaitingVisibleActivities.clear();
947                        mStackSupervisor.scheduleIdleLocked();
948                    }
949                }
950                service.scheduleAppGcsLocked();
951            }
952        }
953    }
954
955    public void windowsGone() {
956        if (ActivityManagerService.DEBUG_SWITCH) Log.v(
957                ActivityManagerService.TAG, "windowsGone(): " + this);
958        nowVisible = false;
959    }
960
961    private ActivityRecord getWaitingHistoryRecordLocked() {
962        // First find the real culprit...  if we are waiting
963        // for another app to start, then we have paused dispatching
964        // for this activity.
965        ActivityRecord r = this;
966        if (r.waitingVisible) {
967            final ActivityStack stack = mStackSupervisor.getFocusedStack();
968            // Hmmm, who might we be waiting for?
969            r = stack.mResumedActivity;
970            if (r == null) {
971                r = stack.mPausingActivity;
972            }
973            // Both of those null?  Fall back to 'this' again
974            if (r == null) {
975                r = this;
976            }
977        }
978
979        return r;
980    }
981
982    public boolean keyDispatchingTimedOut(String reason) {
983        ActivityRecord r;
984        ProcessRecord anrApp;
985        synchronized(service) {
986            r = getWaitingHistoryRecordLocked();
987            anrApp = r != null ? r.app : null;
988        }
989        return service.inputDispatchingTimedOut(anrApp, r, this, false, reason);
990    }
991
992    /** Returns the key dispatching timeout for this application token. */
993    public long getKeyDispatchingTimeout() {
994        synchronized(service) {
995            ActivityRecord r = getWaitingHistoryRecordLocked();
996            return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
997        }
998    }
999
1000    /**
1001     * This method will return true if the activity is either visible, is becoming visible, is
1002     * currently pausing, or is resumed.
1003     */
1004    public boolean isInterestingToUserLocked() {
1005        return visible || nowVisible || state == ActivityState.PAUSING ||
1006                state == ActivityState.RESUMED;
1007    }
1008
1009    public void setSleeping(boolean _sleeping) {
1010        if (sleeping == _sleeping) {
1011            return;
1012        }
1013        if (app != null && app.thread != null) {
1014            try {
1015                app.thread.scheduleSleeping(appToken, _sleeping);
1016                if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) {
1017                    mStackSupervisor.mGoingToSleepActivities.add(this);
1018                }
1019                sleeping = _sleeping;
1020            } catch (RemoteException e) {
1021                Slog.w(TAG, "Exception thrown when sleeping: " + intent.getComponent(), e);
1022            }
1023        }
1024    }
1025
1026    static void activityResumedLocked(IBinder token) {
1027        final ActivityRecord r = ActivityRecord.forToken(token);
1028        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
1029        r.icicle = null;
1030        r.haveState = false;
1031    }
1032
1033    static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
1034        final ActivityRecord r = ActivityRecord.forToken(token);
1035        if (r == null) {
1036            return -1;
1037        }
1038        final TaskRecord task = r.task;
1039        switch (task.mActivities.indexOf(r)) {
1040            case -1: return -1;
1041            case 0: return task.taskId;
1042            default: return onlyRoot ? -1 : task.taskId;
1043        }
1044    }
1045
1046    static ActivityRecord isInStackLocked(IBinder token) {
1047        final ActivityRecord r = ActivityRecord.forToken(token);
1048        if (r != null) {
1049            return r.task.stack.isInStackLocked(token);
1050        }
1051        return null;
1052    }
1053
1054    static ActivityStack getStackLocked(IBinder token) {
1055        final ActivityRecord r = ActivityRecord.isInStackLocked(token);
1056        if (r != null) {
1057            return r.task.stack;
1058        }
1059        return null;
1060    }
1061
1062    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
1063        out.attribute(null, ATTR_ID, String.valueOf(createTime));
1064        out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
1065        if (launchedFromPackage != null) {
1066            out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
1067        }
1068        if (resolvedType != null) {
1069            out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
1070        }
1071        out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified));
1072        out.attribute(null, ATTR_USERID, String.valueOf(userId));
1073        if (taskDescription != null) {
1074            final String label = taskDescription.getLabel();
1075            if (label != null) {
1076                out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
1077            }
1078            final int colorPrimary = taskDescription.getPrimaryColor();
1079            if (colorPrimary != 0) {
1080                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
1081            }
1082            final Bitmap icon = taskDescription.getIcon();
1083            if (icon != null) {
1084                TaskPersister.saveImage(icon, String.valueOf(task.taskId) + ACTIVITY_ICON_SUFFIX +
1085                        createTime);
1086            }
1087        }
1088
1089        out.startTag(null, TAG_INTENT);
1090        intent.saveToXml(out);
1091        out.endTag(null, TAG_INTENT);
1092
1093        if (isPersistable() && persistentState != null) {
1094            out.startTag(null, TAG_PERSISTABLEBUNDLE);
1095            persistentState.saveToXml(out);
1096            out.endTag(null, TAG_PERSISTABLEBUNDLE);
1097        }
1098    }
1099
1100    static ActivityRecord restoreFromXml(XmlPullParser in, int taskId,
1101            ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException {
1102        Intent intent = null;
1103        PersistableBundle persistentState = null;
1104        int launchedFromUid = 0;
1105        String launchedFromPackage = null;
1106        String resolvedType = null;
1107        boolean componentSpecified = false;
1108        int userId = 0;
1109        String activityLabel = null;
1110        int activityColor = 0;
1111        long createTime = -1;
1112        final int outerDepth = in.getDepth();
1113
1114        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
1115            final String attrName = in.getAttributeName(attrNdx);
1116            final String attrValue = in.getAttributeValue(attrNdx);
1117            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: attribute name=" +
1118                    attrName + " value=" + attrValue);
1119            if (ATTR_ID.equals(attrName)) {
1120                createTime = Long.valueOf(attrValue);
1121            } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) {
1122                launchedFromUid = Integer.valueOf(attrValue);
1123            } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) {
1124                launchedFromPackage = attrValue;
1125            } else if (ATTR_RESOLVEDTYPE.equals(attrName)) {
1126                resolvedType = attrValue;
1127            } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) {
1128                componentSpecified = Boolean.valueOf(attrValue);
1129            } else if (ATTR_USERID.equals(attrName)) {
1130                userId = Integer.valueOf(attrValue);
1131            } else if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
1132                activityLabel = attrValue;
1133            } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
1134                activityColor = (int) Long.parseLong(attrValue, 16);
1135            } else {
1136                Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName);
1137            }
1138        }
1139
1140        int event;
1141        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
1142                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
1143            if (event == XmlPullParser.START_TAG) {
1144                final String name = in.getName();
1145                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1146                        "ActivityRecord: START_TAG name=" + name);
1147                if (TAG_INTENT.equals(name)) {
1148                    intent = Intent.restoreFromXml(in);
1149                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1150                            "ActivityRecord: intent=" + intent);
1151                } else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
1152                    persistentState = PersistableBundle.restoreFromXml(in);
1153                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1154                            "ActivityRecord: persistentState=" + persistentState);
1155                } else {
1156                    Slog.w(TAG, "restoreActivity: unexpected name=" + name);
1157                    XmlUtils.skipCurrentTag(in);
1158                }
1159            }
1160        }
1161
1162        if (intent == null) {
1163            throw new XmlPullParserException("restoreActivity error intent=" + intent);
1164        }
1165
1166        final ActivityManagerService service = stackSupervisor.mService;
1167        final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null,
1168                null, userId);
1169        if (aInfo == null) {
1170            throw new XmlPullParserException("restoreActivity resolver error.");
1171        }
1172        final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid,
1173                launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(),
1174                null, null, 0, componentSpecified, stackSupervisor, null, null);
1175
1176        r.persistentState = persistentState;
1177
1178        Bitmap icon = null;
1179        if (createTime >= 0) {
1180            icon = TaskPersister.restoreImage(String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX +
1181                    createTime);
1182        }
1183        r.taskDescription = new TaskDescription(activityLabel, icon, activityColor);
1184        r.createTime = createTime;
1185
1186        return r;
1187    }
1188
1189    private static String activityTypeToString(int type) {
1190        switch (type) {
1191            case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
1192            case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
1193            case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
1194            default: return Integer.toString(type);
1195        }
1196    }
1197
1198    @Override
1199    public String toString() {
1200        if (stringName != null) {
1201            return stringName + " t" + (task == null ? -1 : task.taskId) +
1202                    (finishing ? " f}" : "}");
1203        }
1204        StringBuilder sb = new StringBuilder(128);
1205        sb.append("ActivityRecord{");
1206        sb.append(Integer.toHexString(System.identityHashCode(this)));
1207        sb.append(" u");
1208        sb.append(userId);
1209        sb.append(' ');
1210        sb.append(intent.getComponent().flattenToShortString());
1211        stringName = sb.toString();
1212        return toString();
1213    }
1214}
1215