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