ActivityRecord.java revision d38aed81420d7d992f65ef2efb5f69c1900fc61d
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.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
572    }
573
574    void makeFinishing() {
575        if (!finishing) {
576            finishing = true;
577            if (stopped) {
578                clearOptionsLocked();
579            }
580        }
581    }
582
583    boolean isRootActivity() {
584        final ArrayList<ActivityRecord> activities = task.mActivities;
585        return activities.size() == 0 || this == activities.get(0);
586    }
587
588    UriPermissionOwner getUriPermissionsLocked() {
589        if (uriPermissions == null) {
590            uriPermissions = new UriPermissionOwner(service, this);
591        }
592        return uriPermissions;
593    }
594
595    void addResultLocked(ActivityRecord from, String resultWho,
596            int requestCode, int resultCode,
597            Intent resultData) {
598        ActivityResult r = new ActivityResult(from, resultWho,
599                requestCode, resultCode, resultData);
600        if (results == null) {
601            results = new ArrayList<ResultInfo>();
602        }
603        results.add(r);
604    }
605
606    void removeResultsLocked(ActivityRecord from, String resultWho,
607            int requestCode) {
608        if (results != null) {
609            for (int i=results.size()-1; i>=0; i--) {
610                ActivityResult r = (ActivityResult)results.get(i);
611                if (r.mFrom != from) continue;
612                if (r.mResultWho == null) {
613                    if (resultWho != null) continue;
614                } else {
615                    if (!r.mResultWho.equals(resultWho)) continue;
616                }
617                if (r.mRequestCode != requestCode) continue;
618
619                results.remove(i);
620            }
621        }
622    }
623
624    void addNewIntentLocked(Intent intent) {
625        if (newIntents == null) {
626            newIntents = new ArrayList<Intent>();
627        }
628        newIntents.add(intent);
629    }
630
631    /**
632     * Deliver a new Intent to an existing activity, so that its onNewIntent()
633     * method will be called at the proper time.
634     */
635    final void deliverNewIntentLocked(int callingUid, Intent intent) {
636        // The activity now gets access to the data associated with this Intent.
637        service.grantUriPermissionFromIntentLocked(callingUid, packageName,
638                intent, getUriPermissionsLocked());
639        // We want to immediately deliver the intent to the activity if
640        // it is currently the top resumed activity...  however, if the
641        // device is sleeping, then all activities are stopped, so in that
642        // case we will deliver it if this is the current top activity on its
643        // stack.
644        boolean unsent = true;
645        if ((state == ActivityState.RESUMED || (service.isSleeping()
646                        && task.stack.topRunningActivityLocked(null) == this))
647                && app != null && app.thread != null) {
648            try {
649                ArrayList<Intent> ar = new ArrayList<Intent>();
650                intent = new Intent(intent);
651                ar.add(intent);
652                app.thread.scheduleNewIntent(ar, appToken);
653                unsent = false;
654            } catch (RemoteException e) {
655                Slog.w(ActivityManagerService.TAG,
656                        "Exception thrown sending new intent to " + this, e);
657            } catch (NullPointerException e) {
658                Slog.w(ActivityManagerService.TAG,
659                        "Exception thrown sending new intent to " + this, e);
660            }
661        }
662        if (unsent) {
663            addNewIntentLocked(new Intent(intent));
664        }
665    }
666
667    void updateOptionsLocked(Bundle options) {
668        if (options != null) {
669            if (pendingOptions != null) {
670                pendingOptions.abort();
671            }
672            pendingOptions = new ActivityOptions(options);
673        }
674    }
675
676    void updateOptionsLocked(ActivityOptions options) {
677        if (options != null) {
678            if (pendingOptions != null) {
679                pendingOptions.abort();
680            }
681            pendingOptions = options;
682        }
683    }
684
685    void applyOptionsLocked() {
686        if (pendingOptions != null
687                && pendingOptions.getAnimationType() != ActivityOptions.ANIM_SCENE_TRANSITION) {
688            final int animationType = pendingOptions.getAnimationType();
689            switch (animationType) {
690                case ActivityOptions.ANIM_CUSTOM:
691                    service.mWindowManager.overridePendingAppTransition(
692                            pendingOptions.getPackageName(),
693                            pendingOptions.getCustomEnterResId(),
694                            pendingOptions.getCustomExitResId(),
695                            pendingOptions.getOnAnimationStartListener());
696                    break;
697                case ActivityOptions.ANIM_SCALE_UP:
698                    service.mWindowManager.overridePendingAppTransitionScaleUp(
699                            pendingOptions.getStartX(), pendingOptions.getStartY(),
700                            pendingOptions.getStartWidth(), pendingOptions.getStartHeight());
701                    if (intent.getSourceBounds() == null) {
702                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
703                                pendingOptions.getStartY(),
704                                pendingOptions.getStartX()+pendingOptions.getStartWidth(),
705                                pendingOptions.getStartY()+pendingOptions.getStartHeight()));
706                    }
707                    break;
708                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
709                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
710                    boolean scaleUp = (animationType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
711                    service.mWindowManager.overridePendingAppTransitionThumb(
712                            pendingOptions.getThumbnail(),
713                            pendingOptions.getStartX(), pendingOptions.getStartY(),
714                            pendingOptions.getOnAnimationStartListener(),
715                            scaleUp);
716                    if (intent.getSourceBounds() == null) {
717                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
718                                pendingOptions.getStartY(),
719                                pendingOptions.getStartX()
720                                        + pendingOptions.getThumbnail().getWidth(),
721                                pendingOptions.getStartY()
722                                        + pendingOptions.getThumbnail().getHeight()));
723                    }
724                    break;
725                default:
726                    Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
727                    break;
728            }
729            pendingOptions = null;
730        }
731    }
732
733    ActivityOptions getOptionsForTargetActivityLocked() {
734        return pendingOptions != null ? pendingOptions.forTargetActivity() : null;
735    }
736
737    void clearOptionsLocked() {
738        if (pendingOptions != null) {
739            pendingOptions.abort();
740            pendingOptions = null;
741        }
742    }
743
744    ActivityOptions takeOptionsLocked() {
745        ActivityOptions opts = pendingOptions;
746        pendingOptions = null;
747        return opts;
748    }
749
750    void removeUriPermissionsLocked() {
751        if (uriPermissions != null) {
752            uriPermissions.removeUriPermissionsLocked();
753            uriPermissions = null;
754        }
755    }
756
757    void pauseKeyDispatchingLocked() {
758        if (!keysPaused) {
759            keysPaused = true;
760            service.mWindowManager.pauseKeyDispatching(appToken);
761        }
762    }
763
764    void resumeKeyDispatchingLocked() {
765        if (keysPaused) {
766            keysPaused = false;
767            service.mWindowManager.resumeKeyDispatching(appToken);
768        }
769    }
770
771    void updateThumbnail(Bitmap newThumbnail, CharSequence description) {
772        if (thumbHolder != null) {
773            if (newThumbnail != null) {
774                if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
775                        "Setting thumbnail of " + this + " holder " + thumbHolder
776                        + " to " + newThumbnail);
777                thumbHolder.lastThumbnail = newThumbnail;
778                if (isPersistable()) {
779                    mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
780                }
781            }
782            thumbHolder.lastDescription = description;
783        }
784    }
785
786    void startLaunchTickingLocked() {
787        if (ActivityManagerService.IS_USER_BUILD) {
788            return;
789        }
790        if (launchTickTime == 0) {
791            launchTickTime = SystemClock.uptimeMillis();
792            continueLaunchTickingLocked();
793        }
794    }
795
796    boolean continueLaunchTickingLocked() {
797        if (launchTickTime != 0) {
798            final ActivityStack stack = task.stack;
799            Message msg = stack.mHandler.obtainMessage(ActivityStack.LAUNCH_TICK_MSG, this);
800            stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
801            stack.mHandler.sendMessageDelayed(msg, ActivityStack.LAUNCH_TICK);
802            return true;
803        }
804        return false;
805    }
806
807    void finishLaunchTickingLocked() {
808        launchTickTime = 0;
809        task.stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
810    }
811
812    // IApplicationToken
813
814    public boolean mayFreezeScreenLocked(ProcessRecord app) {
815        // Only freeze the screen if this activity is currently attached to
816        // an application, and that application is not blocked or unresponding.
817        // In any other case, we can't count on getting the screen unfrozen,
818        // so it is best to leave as-is.
819        return app != null && !app.crashing && !app.notResponding;
820    }
821
822    public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
823        if (mayFreezeScreenLocked(app)) {
824            service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
825        }
826    }
827
828    public void stopFreezingScreenLocked(boolean force) {
829        if (force || frozenBeforeDestroy) {
830            frozenBeforeDestroy = false;
831            service.mWindowManager.stopAppFreezingScreen(appToken, force);
832        }
833    }
834
835    public void reportFullyDrawnLocked() {
836        final long curTime = SystemClock.uptimeMillis();
837        if (displayStartTime != 0) {
838            reportLaunchTimeLocked(curTime);
839        }
840        if (fullyDrawnStartTime != 0) {
841            final ActivityStack stack = task.stack;
842            final long thisTime = curTime - fullyDrawnStartTime;
843            final long totalTime = stack.mFullyDrawnStartTime != 0
844                    ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
845            if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
846                Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
847                EventLog.writeEvent(EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME,
848                        userId, System.identityHashCode(this), shortComponentName,
849                        thisTime, totalTime);
850                StringBuilder sb = service.mStringBuilder;
851                sb.setLength(0);
852                sb.append("Fully drawn ");
853                sb.append(shortComponentName);
854                sb.append(": ");
855                TimeUtils.formatDuration(thisTime, sb);
856                if (thisTime != totalTime) {
857                    sb.append(" (total ");
858                    TimeUtils.formatDuration(totalTime, sb);
859                    sb.append(")");
860                }
861                Log.i(ActivityManagerService.TAG, sb.toString());
862            }
863            if (totalTime > 0) {
864                service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime);
865            }
866            fullyDrawnStartTime = 0;
867            stack.mFullyDrawnStartTime = 0;
868        }
869    }
870
871    private void reportLaunchTimeLocked(final long curTime) {
872        final ActivityStack stack = task.stack;
873        final long thisTime = curTime - displayStartTime;
874        final long totalTime = stack.mLaunchStartTime != 0
875                ? (curTime - stack.mLaunchStartTime) : thisTime;
876        if (ActivityManagerService.SHOW_ACTIVITY_START_TIME) {
877            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching", 0);
878            EventLog.writeEvent(EventLogTags.AM_ACTIVITY_LAUNCH_TIME,
879                    userId, System.identityHashCode(this), shortComponentName,
880                    thisTime, totalTime);
881            StringBuilder sb = service.mStringBuilder;
882            sb.setLength(0);
883            sb.append("Displayed ");
884            sb.append(shortComponentName);
885            sb.append(": ");
886            TimeUtils.formatDuration(thisTime, sb);
887            if (thisTime != totalTime) {
888                sb.append(" (total ");
889                TimeUtils.formatDuration(totalTime, sb);
890                sb.append(")");
891            }
892            Log.i(ActivityManagerService.TAG, sb.toString());
893        }
894        mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
895        if (totalTime > 0) {
896            service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
897        }
898        displayStartTime = 0;
899        stack.mLaunchStartTime = 0;
900    }
901
902    public void windowsDrawn() {
903        synchronized(service) {
904            if (displayStartTime != 0) {
905                reportLaunchTimeLocked(SystemClock.uptimeMillis());
906            }
907            startTime = 0;
908            finishLaunchTickingLocked();
909            if (task != null) {
910                task.hasBeenVisible = true;
911            }
912        }
913    }
914
915    public void windowsVisible() {
916        synchronized(service) {
917            mStackSupervisor.reportActivityVisibleLocked(this);
918            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
919                    ActivityManagerService.TAG, "windowsVisible(): " + this);
920            if (!nowVisible) {
921                nowVisible = true;
922                lastVisibleTime = SystemClock.uptimeMillis();
923                if (!idle) {
924                    // Instead of doing the full stop routine here, let's just
925                    // hide any activities we now can, and let them stop when
926                    // the normal idle happens.
927                    mStackSupervisor.processStoppingActivitiesLocked(false);
928                } else {
929                    // If this activity was already idle, then we now need to
930                    // make sure we perform the full stop of any activities
931                    // that are waiting to do so.  This is because we won't
932                    // do that while they are still waiting for this one to
933                    // become visible.
934                    final int N = mStackSupervisor.mWaitingVisibleActivities.size();
935                    if (N > 0) {
936                        for (int i=0; i<N; i++) {
937                            ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
938                            r.waitingVisible = false;
939                            if (ActivityManagerService.DEBUG_SWITCH) Log.v(
940                                    ActivityManagerService.TAG,
941                                    "Was waiting for visible: " + r);
942                        }
943                        mStackSupervisor.mWaitingVisibleActivities.clear();
944                        mStackSupervisor.scheduleIdleLocked();
945                    }
946                }
947                service.scheduleAppGcsLocked();
948            }
949        }
950    }
951
952    public void windowsGone() {
953        if (ActivityManagerService.DEBUG_SWITCH) Log.v(
954                ActivityManagerService.TAG, "windowsGone(): " + this);
955        nowVisible = false;
956    }
957
958    private ActivityRecord getWaitingHistoryRecordLocked() {
959        // First find the real culprit...  if we are waiting
960        // for another app to start, then we have paused dispatching
961        // for this activity.
962        ActivityRecord r = this;
963        if (r.waitingVisible) {
964            final ActivityStack stack = mStackSupervisor.getFocusedStack();
965            // Hmmm, who might we be waiting for?
966            r = stack.mResumedActivity;
967            if (r == null) {
968                r = stack.mPausingActivity;
969            }
970            // Both of those null?  Fall back to 'this' again
971            if (r == null) {
972                r = this;
973            }
974        }
975
976        return r;
977    }
978
979    public boolean keyDispatchingTimedOut(String reason) {
980        ActivityRecord r;
981        ProcessRecord anrApp;
982        synchronized(service) {
983            r = getWaitingHistoryRecordLocked();
984            anrApp = r != null ? r.app : null;
985        }
986        return service.inputDispatchingTimedOut(anrApp, r, this, false, reason);
987    }
988
989    /** Returns the key dispatching timeout for this application token. */
990    public long getKeyDispatchingTimeout() {
991        synchronized(service) {
992            ActivityRecord r = getWaitingHistoryRecordLocked();
993            return ActivityManagerService.getInputDispatchingTimeoutLocked(r);
994        }
995    }
996
997    /**
998     * This method will return true if the activity is either visible, is becoming visible, is
999     * currently pausing, or is resumed.
1000     */
1001    public boolean isInterestingToUserLocked() {
1002        return visible || nowVisible || state == ActivityState.PAUSING ||
1003                state == ActivityState.RESUMED;
1004    }
1005
1006    public void setSleeping(boolean _sleeping) {
1007        if (sleeping == _sleeping) {
1008            return;
1009        }
1010        if (app != null && app.thread != null) {
1011            try {
1012                app.thread.scheduleSleeping(appToken, _sleeping);
1013                if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) {
1014                    mStackSupervisor.mGoingToSleepActivities.add(this);
1015                }
1016                sleeping = _sleeping;
1017            } catch (RemoteException e) {
1018                Slog.w(TAG, "Exception thrown when sleeping: " + intent.getComponent(), e);
1019            }
1020        }
1021    }
1022
1023    static void activityResumedLocked(IBinder token) {
1024        final ActivityRecord r = ActivityRecord.forToken(token);
1025        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
1026        r.icicle = null;
1027        r.haveState = false;
1028    }
1029
1030    static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
1031        final ActivityRecord r = ActivityRecord.forToken(token);
1032        if (r == null) {
1033            return -1;
1034        }
1035        final TaskRecord task = r.task;
1036        switch (task.mActivities.indexOf(r)) {
1037            case -1: return -1;
1038            case 0: return task.taskId;
1039            default: return onlyRoot ? -1 : task.taskId;
1040        }
1041    }
1042
1043    static ActivityRecord isInStackLocked(IBinder token) {
1044        final ActivityRecord r = ActivityRecord.forToken(token);
1045        if (r != null) {
1046            return r.task.stack.isInStackLocked(token);
1047        }
1048        return null;
1049    }
1050
1051    static ActivityStack getStackLocked(IBinder token) {
1052        final ActivityRecord r = ActivityRecord.isInStackLocked(token);
1053        if (r != null) {
1054            return r.task.stack;
1055        }
1056        return null;
1057    }
1058
1059    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
1060        out.attribute(null, ATTR_ID, String.valueOf(createTime));
1061        out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
1062        if (launchedFromPackage != null) {
1063            out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
1064        }
1065        if (resolvedType != null) {
1066            out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
1067        }
1068        out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified));
1069        out.attribute(null, ATTR_USERID, String.valueOf(userId));
1070        if (taskDescription != null) {
1071            final String label = taskDescription.getLabel();
1072            if (label != null) {
1073                out.attribute(null, ATTR_TASKDESCRIPTIONLABEL, label);
1074            }
1075            final int colorPrimary = taskDescription.getPrimaryColor();
1076            if (colorPrimary != 0) {
1077                out.attribute(null, ATTR_TASKDESCRIPTIONCOLOR, Integer.toHexString(colorPrimary));
1078            }
1079            final Bitmap icon = taskDescription.getIcon();
1080            if (icon != null) {
1081                TaskPersister.saveImage(icon, String.valueOf(task.taskId) + ACTIVITY_ICON_SUFFIX +
1082                        createTime);
1083            }
1084        }
1085
1086        out.startTag(null, TAG_INTENT);
1087        intent.saveToXml(out);
1088        out.endTag(null, TAG_INTENT);
1089
1090        if (isPersistable() && persistentState != null) {
1091            out.startTag(null, TAG_PERSISTABLEBUNDLE);
1092            persistentState.saveToXml(out);
1093            out.endTag(null, TAG_PERSISTABLEBUNDLE);
1094        }
1095    }
1096
1097    static ActivityRecord restoreFromXml(XmlPullParser in, int taskId,
1098            ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException {
1099        Intent intent = null;
1100        PersistableBundle persistentState = null;
1101        int launchedFromUid = 0;
1102        String launchedFromPackage = null;
1103        String resolvedType = null;
1104        boolean componentSpecified = false;
1105        int userId = 0;
1106        String activityLabel = null;
1107        int activityColor = 0;
1108        long createTime = -1;
1109        final int outerDepth = in.getDepth();
1110
1111        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
1112            final String attrName = in.getAttributeName(attrNdx);
1113            final String attrValue = in.getAttributeValue(attrNdx);
1114            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "ActivityRecord: attribute name=" +
1115                    attrName + " value=" + attrValue);
1116            if (ATTR_ID.equals(attrName)) {
1117                createTime = Long.valueOf(attrValue);
1118            } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) {
1119                launchedFromUid = Integer.valueOf(attrValue);
1120            } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) {
1121                launchedFromPackage = attrValue;
1122            } else if (ATTR_RESOLVEDTYPE.equals(attrName)) {
1123                resolvedType = attrValue;
1124            } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) {
1125                componentSpecified = Boolean.valueOf(attrValue);
1126            } else if (ATTR_USERID.equals(attrName)) {
1127                userId = Integer.valueOf(attrValue);
1128            } else if (ATTR_TASKDESCRIPTIONLABEL.equals(attrName)) {
1129                activityLabel = attrValue;
1130            } else if (ATTR_TASKDESCRIPTIONCOLOR.equals(attrName)) {
1131                activityColor = (int) Long.parseLong(attrValue, 16);
1132            } else {
1133                Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName);
1134            }
1135        }
1136
1137        int event;
1138        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
1139                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
1140            if (event == XmlPullParser.START_TAG) {
1141                final String name = in.getName();
1142                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1143                        "ActivityRecord: START_TAG name=" + name);
1144                if (TAG_INTENT.equals(name)) {
1145                    intent = Intent.restoreFromXml(in);
1146                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1147                            "ActivityRecord: intent=" + intent);
1148                } else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
1149                    persistentState = PersistableBundle.restoreFromXml(in);
1150                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
1151                            "ActivityRecord: persistentState=" + persistentState);
1152                } else {
1153                    Slog.w(TAG, "restoreActivity: unexpected name=" + name);
1154                    XmlUtils.skipCurrentTag(in);
1155                }
1156            }
1157        }
1158
1159        if (intent == null) {
1160            throw new XmlPullParserException("restoreActivity error intent=" + intent);
1161        }
1162
1163        final ActivityManagerService service = stackSupervisor.mService;
1164        final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null,
1165                null, userId);
1166        if (aInfo == null) {
1167            throw new XmlPullParserException("restoreActivity resolver error.");
1168        }
1169        final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid,
1170                launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(),
1171                null, null, 0, componentSpecified, stackSupervisor, null, null);
1172
1173        r.persistentState = persistentState;
1174
1175        Bitmap icon = null;
1176        if (createTime >= 0) {
1177            icon = TaskPersister.restoreImage(String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX +
1178                    createTime);
1179        }
1180        r.taskDescription = new TaskDescription(activityLabel, icon, activityColor);
1181        r.createTime = createTime;
1182
1183        return r;
1184    }
1185
1186    private static String activityTypeToString(int type) {
1187        switch (type) {
1188            case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
1189            case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
1190            case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
1191            default: return Integer.toString(type);
1192        }
1193    }
1194
1195    @Override
1196    public String toString() {
1197        if (stringName != null) {
1198            return stringName + " t" + (task == null ? -1 : task.taskId) +
1199                    (finishing ? " f}" : "}");
1200        }
1201        StringBuilder sb = new StringBuilder(128);
1202        sb.append("ActivityRecord{");
1203        sb.append(Integer.toHexString(System.identityHashCode(this)));
1204        sb.append(" u");
1205        sb.append(userId);
1206        sb.append(' ');
1207        sb.append(intent.getComponent().flattenToShortString());
1208        stringName = sb.toString();
1209        return toString();
1210    }
1211}
1212