Instrumentation.java revision 92a8b22e7410e74e1cba1b856333116652af8a5c
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 android.app;
18
19import android.content.ActivityNotFoundException;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.ActivityInfo;
25import android.content.res.Configuration;
26import android.os.Bundle;
27import android.os.Debug;
28import android.os.IBinder;
29import android.os.MessageQueue;
30import android.os.PerformanceCollector;
31import android.os.Process;
32import android.os.RemoteException;
33import android.os.ServiceManager;
34import android.os.SystemClock;
35import android.util.AndroidRuntimeException;
36import android.util.Log;
37import android.view.IWindowManager;
38import android.view.KeyCharacterMap;
39import android.view.KeyEvent;
40import android.view.MotionEvent;
41import android.view.ViewConfiguration;
42import android.view.Window;
43
44import java.io.File;
45import java.util.ArrayList;
46import java.util.List;
47
48
49/**
50 * Base class for implementing application instrumentation code.  When running
51 * with instrumentation turned on, this class will be instantiated for you
52 * before any of the application code, allowing you to monitor all of the
53 * interaction the system has with the application.  An Instrumentation
54 * implementation is described to the system through an AndroidManifest.xml's
55 * <instrumentation> tag.
56 */
57public class Instrumentation {
58    /**
59     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
60     * identifies the class that is writing the report.  This can be used to provide more structured
61     * logging or reporting capabilities in the IInstrumentationWatcher.
62     */
63    public static final String REPORT_KEY_IDENTIFIER = "id";
64    /**
65     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
66     * identifies a string which can simply be printed to the output stream.  Using these streams
67     * provides a "pretty printer" version of the status & final packets.  Any bundles including
68     * this key should also include the complete set of raw key/value pairs, so that the
69     * instrumentation can also be launched, and results collected, by an automated system.
70     */
71    public static final String REPORT_KEY_STREAMRESULT = "stream";
72
73    private static final String TAG = "Instrumentation";
74
75    private final Object mSync = new Object();
76    private ActivityThread mThread = null;
77    private MessageQueue mMessageQueue = null;
78    private Context mInstrContext;
79    private Context mAppContext;
80    private ComponentName mComponent;
81    private Thread mRunner;
82    private List<ActivityWaiter> mWaitingActivities;
83    private List<ActivityMonitor> mActivityMonitors;
84    private IInstrumentationWatcher mWatcher;
85    private boolean mAutomaticPerformanceSnapshots = false;
86    private PerformanceCollector mPerformanceCollector;
87    private Bundle mPerfMetrics = new Bundle();
88
89    public Instrumentation() {
90    }
91
92    /**
93     * Called when the instrumentation is starting, before any application code
94     * has been loaded.  Usually this will be implemented to simply call
95     * {@link #start} to begin the instrumentation thread, which will then
96     * continue execution in {@link #onStart}.
97     *
98     * <p>If you do not need your own thread -- that is you are writing your
99     * instrumentation to be completely asynchronous (returning to the event
100     * loop so that the application can run), you can simply begin your
101     * instrumentation here, for example call {@link Context#startActivity} to
102     * begin the appropriate first activity of the application.
103     *
104     * @param arguments Any additional arguments that were supplied when the
105     *                  instrumentation was started.
106     */
107    public void onCreate(Bundle arguments) {
108    }
109
110    /**
111     * Create and start a new thread in which to run instrumentation.  This new
112     * thread will call to {@link #onStart} where you can implement the
113     * instrumentation.
114     */
115    public void start() {
116        if (mRunner != null) {
117            throw new RuntimeException("Instrumentation already started");
118        }
119        mRunner = new InstrumentationThread("Instr: " + getClass().getName());
120        mRunner.start();
121    }
122
123    /**
124     * Method where the instrumentation thread enters execution.  This allows
125     * you to run your instrumentation code in a separate thread than the
126     * application, so that it can perform blocking operation such as
127     * {@link #sendKeySync} or {@link #startActivitySync}.
128     *
129     * <p>You will typically want to call finish() when this function is done,
130     * to end your instrumentation.
131     */
132    public void onStart() {
133    }
134
135    /**
136     * This is called whenever the system captures an unhandled exception that
137     * was thrown by the application.  The default implementation simply
138     * returns false, allowing normal system handling of the exception to take
139     * place.
140     *
141     * @param obj The client object that generated the exception.  May be an
142     *            Application, Activity, BroadcastReceiver, Service, or null.
143     * @param e The exception that was thrown.
144     *
145     * @return To allow normal system exception process to occur, return false.
146     *         If true is returned, the system will proceed as if the exception
147     *         didn't happen.
148     */
149    public boolean onException(Object obj, Throwable e) {
150        return false;
151    }
152
153    /**
154     * Provide a status report about the application.
155     *
156     * @param resultCode Current success/failure of instrumentation.
157     * @param results Any results to send back to the code that started the instrumentation.
158     */
159    public void sendStatus(int resultCode, Bundle results) {
160        if (mWatcher != null) {
161            try {
162                mWatcher.instrumentationStatus(mComponent, resultCode, results);
163            }
164            catch (RemoteException e) {
165                mWatcher = null;
166            }
167        }
168    }
169
170    /**
171     * Terminate instrumentation of the application.  This will cause the
172     * application process to exit, removing this instrumentation from the next
173     * time the application is started.
174     *
175     * @param resultCode Overall success/failure of instrumentation.
176     * @param results Any results to send back to the code that started the
177     *                instrumentation.
178     */
179    public void finish(int resultCode, Bundle results) {
180        if (mAutomaticPerformanceSnapshots) {
181            endPerformanceSnapshot();
182        }
183        if (mPerfMetrics != null) {
184            results.putAll(mPerfMetrics);
185        }
186        mThread.finishInstrumentation(resultCode, results);
187    }
188
189    public void setAutomaticPerformanceSnapshots() {
190        mAutomaticPerformanceSnapshots = true;
191        mPerformanceCollector = new PerformanceCollector();
192    }
193
194    public void startPerformanceSnapshot() {
195        if (!isProfiling()) {
196            mPerformanceCollector.beginSnapshot(null);
197        }
198    }
199
200    public void endPerformanceSnapshot() {
201        if (!isProfiling()) {
202            mPerfMetrics = mPerformanceCollector.endSnapshot();
203        }
204    }
205
206    /**
207     * Called when the instrumented application is stopping, after all of the
208     * normal application cleanup has occurred.
209     */
210    public void onDestroy() {
211    }
212
213    /**
214     * Return the Context of this instrumentation's package.  Note that this is
215     * often different than the Context of the application being
216     * instrumentated, since the instrumentation code often lives is a
217     * different package than that of the application it is running against.
218     * See {@link #getTargetContext} to retrieve a Context for the target
219     * application.
220     *
221     * @return The instrumentation's package context.
222     *
223     * @see #getTargetContext
224     */
225    public Context getContext() {
226        return mInstrContext;
227    }
228
229    /**
230     * Returns complete component name of this instrumentation.
231     *
232     * @return Returns the complete component name for this instrumentation.
233     */
234    public ComponentName getComponentName() {
235        return mComponent;
236    }
237
238    /**
239     * Return a Context for the target application being instrumented.  Note
240     * that this is often different than the Context of the instrumentation
241     * code, since the instrumentation code often lives is a different package
242     * than that of the application it is running against. See
243     * {@link #getContext} to retrieve a Context for the instrumentation code.
244     *
245     * @return A Context in the target application.
246     *
247     * @see #getContext
248     */
249    public Context getTargetContext() {
250        return mAppContext;
251    }
252
253    /**
254     * Check whether this instrumentation was started with profiling enabled.
255     *
256     * @return Returns true if profiling was enabled when starting, else false.
257     */
258    public boolean isProfiling() {
259        return mThread.isProfiling();
260    }
261
262    /**
263     * This method will start profiling if isProfiling() returns true. You should
264     * only call this method if you set the handleProfiling attribute in the
265     * manifest file for this Instrumentation to true.
266     */
267    public void startProfiling() {
268        if (mThread.isProfiling()) {
269            File file = new File(mThread.getProfileFilePath());
270            file.getParentFile().mkdirs();
271            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
272        }
273    }
274
275    /**
276     * Stops profiling if isProfiling() returns true.
277     */
278    public void stopProfiling() {
279        if (mThread.isProfiling()) {
280            Debug.stopMethodTracing();
281        }
282    }
283
284    /**
285     * Force the global system in or out of touch mode.  This can be used if
286     * your instrumentation relies on the UI being in one more or the other
287     * when it starts.
288     *
289     * @param inTouch Set to true to be in touch mode, false to be in
290     * focus mode.
291     */
292    public void setInTouchMode(boolean inTouch) {
293        try {
294            IWindowManager.Stub.asInterface(
295                    ServiceManager.getService("window")).setInTouchMode(inTouch);
296        } catch (RemoteException e) {
297            // Shouldn't happen!
298        }
299    }
300
301    /**
302     * Schedule a callback for when the application's main thread goes idle
303     * (has no more events to process).
304     *
305     * @param recipient Called the next time the thread's message queue is
306     *                  idle.
307     */
308    public void waitForIdle(Runnable recipient) {
309        mMessageQueue.addIdleHandler(new Idler(recipient));
310        mThread.getHandler().post(new EmptyRunnable());
311    }
312
313    /**
314     * Synchronously wait for the application to be idle.  Can not be called
315     * from the main application thread -- use {@link #start} to execute
316     * instrumentation in its own thread.
317     */
318    public void waitForIdleSync() {
319        validateNotAppThread();
320        Idler idler = new Idler(null);
321        mMessageQueue.addIdleHandler(idler);
322        mThread.getHandler().post(new EmptyRunnable());
323        idler.waitForIdle();
324    }
325
326    /**
327     * Execute a call on the application's main thread, blocking until it is
328     * complete.  Useful for doing things that are not thread-safe, such as
329     * looking at or modifying the view hierarchy.
330     *
331     * @param runner The code to run on the main thread.
332     */
333    public void runOnMainSync(Runnable runner) {
334        validateNotAppThread();
335        SyncRunnable sr = new SyncRunnable(runner);
336        mThread.getHandler().post(sr);
337        sr.waitForComplete();
338    }
339
340    /**
341     * Start a new activity and wait for it to begin running before returning.
342     * In addition to being synchronous, this method as some semantic
343     * differences from the standard {@link Context#startActivity} call: the
344     * activity component is resolved before talking with the activity manager
345     * (its class name is specified in the Intent that this method ultimately
346     * starts), and it does not allow you to start activities that run in a
347     * different process.  In addition, if the given Intent resolves to
348     * multiple activities, instead of displaying a dialog for the user to
349     * select an activity, an exception will be thrown.
350     *
351     * <p>The function returns as soon as the activity goes idle following the
352     * call to its {@link Activity#onCreate}.  Generally this means it has gone
353     * through the full initialization including {@link Activity#onResume} and
354     * drawn and displayed its initial window.
355     *
356     * @param intent Description of the activity to start.
357     *
358     * @see Context#startActivity
359     */
360    public Activity startActivitySync(Intent intent) {
361        validateNotAppThread();
362
363        synchronized (mSync) {
364            intent = new Intent(intent);
365
366            ActivityInfo ai = intent.resolveActivityInfo(
367                getTargetContext().getPackageManager(), 0);
368            if (ai == null) {
369                throw new RuntimeException("Unable to resolve activity for: " + intent);
370            }
371            String myProc = mThread.getProcessName();
372            if (!ai.processName.equals(myProc)) {
373                // todo: if this intent is ambiguous, look here to see if
374                // there is a single match that is in our package.
375                throw new RuntimeException("Intent in process "
376                        + myProc + " resolved to different process "
377                        + ai.processName + ": " + intent);
378            }
379
380            intent.setComponent(new ComponentName(
381                    ai.applicationInfo.packageName, ai.name));
382            final ActivityWaiter aw = new ActivityWaiter(intent);
383
384            if (mWaitingActivities == null) {
385                mWaitingActivities = new ArrayList();
386            }
387            mWaitingActivities.add(aw);
388
389            getTargetContext().startActivity(intent);
390
391            do {
392                try {
393                    mSync.wait();
394                } catch (InterruptedException e) {
395                }
396            } while (mWaitingActivities.contains(aw));
397
398            return aw.activity;
399        }
400    }
401
402    /**
403     * Information about a particular kind of Intent that is being monitored.
404     * An instance of this class is added to the
405     * current instrumentation through {@link #addMonitor}; after being added,
406     * when a new activity is being started the monitor will be checked and, if
407     * matching, its hit count updated and (optionally) the call stopped and a
408     * canned result returned.
409     *
410     * <p>An ActivityMonitor can also be used to look for the creation of an
411     * activity, through the {@link #waitForActivity} method.  This will return
412     * after a matching activity has been created with that activity object.
413     */
414    public static class ActivityMonitor {
415        private final IntentFilter mWhich;
416        private final String mClass;
417        private final ActivityResult mResult;
418        private final boolean mBlock;
419
420
421        // This is protected by 'Instrumentation.this.mSync'.
422        /*package*/ int mHits = 0;
423
424        // This is protected by 'this'.
425        /*package*/ Activity mLastActivity = null;
426
427        /**
428         * Create a new ActivityMonitor that looks for a particular kind of
429         * intent to be started.
430         *
431         * @param which The set of intents this monitor is responsible for.
432         * @param result A canned result to return if the monitor is hit; can
433         *               be null.
434         * @param block Controls whether the monitor should block the activity
435         *              start (returning its canned result) or let the call
436         *              proceed.
437         *
438         * @see Instrumentation#addMonitor
439         */
440        public ActivityMonitor(
441            IntentFilter which, ActivityResult result, boolean block) {
442            mWhich = which;
443            mClass = null;
444            mResult = result;
445            mBlock = block;
446        }
447
448        /**
449         * Create a new ActivityMonitor that looks for a specific activity
450         * class to be started.
451         *
452         * @param cls The activity class this monitor is responsible for.
453         * @param result A canned result to return if the monitor is hit; can
454         *               be null.
455         * @param block Controls whether the monitor should block the activity
456         *              start (returning its canned result) or let the call
457         *              proceed.
458         *
459         * @see Instrumentation#addMonitor
460         */
461        public ActivityMonitor(
462            String cls, ActivityResult result, boolean block) {
463            mWhich = null;
464            mClass = cls;
465            mResult = result;
466            mBlock = block;
467        }
468
469        /**
470         * Retrieve the filter associated with this ActivityMonitor.
471         */
472        public final IntentFilter getFilter() {
473            return mWhich;
474        }
475
476        /**
477         * Retrieve the result associated with this ActivityMonitor, or null if
478         * none.
479         */
480        public final ActivityResult getResult() {
481            return mResult;
482        }
483
484        /**
485         * Check whether this monitor blocks activity starts (not allowing the
486         * actual activity to run) or allows them to execute normally.
487         */
488        public final boolean isBlocking() {
489            return mBlock;
490        }
491
492        /**
493         * Retrieve the number of times the monitor has been hit so far.
494         */
495        public final int getHits() {
496            return mHits;
497        }
498
499        /**
500         * Retrieve the most recent activity class that was seen by this
501         * monitor.
502         */
503        public final Activity getLastActivity() {
504            return mLastActivity;
505        }
506
507        /**
508         * Block until an Activity is created that matches this monitor,
509         * returning the resulting activity.
510         *
511         * @return Activity
512         */
513        public final Activity waitForActivity() {
514            synchronized (this) {
515                while (mLastActivity == null) {
516                    try {
517                        wait();
518                    } catch (InterruptedException e) {
519                    }
520                }
521                Activity res = mLastActivity;
522                mLastActivity = null;
523                return res;
524            }
525        }
526
527        /**
528         * Block until an Activity is created that matches this monitor,
529         * returning the resulting activity or till the timeOut period expires.
530         * If the timeOut expires before the activity is started, return null.
531         *
532         * @param timeOut Time to wait before the activity is created.
533         *
534         * @return Activity
535         */
536        public final Activity waitForActivityWithTimeout(long timeOut) {
537            synchronized (this) {
538                if (mLastActivity == null) {
539                    try {
540                        wait(timeOut);
541                    } catch (InterruptedException e) {
542                    }
543                }
544                if (mLastActivity == null) {
545                    return null;
546                } else {
547                    Activity res = mLastActivity;
548                    mLastActivity = null;
549                    return res;
550                }
551            }
552        }
553
554        final boolean match(Context who,
555                            Activity activity,
556                            Intent intent) {
557            synchronized (this) {
558                if (mWhich != null
559                    && mWhich.match(who.getContentResolver(), intent,
560                                    true, "Instrumentation") < 0) {
561                    return false;
562                }
563                if (mClass != null) {
564                    String cls = null;
565                    if (activity != null) {
566                        cls = activity.getClass().getName();
567                    } else if (intent.getComponent() != null) {
568                        cls = intent.getComponent().getClassName();
569                    }
570                    if (cls == null || !mClass.equals(cls)) {
571                        return false;
572                    }
573                }
574                if (activity != null) {
575                    mLastActivity = activity;
576                    notifyAll();
577                }
578                return true;
579            }
580        }
581    }
582
583    /**
584     * Add a new {@link ActivityMonitor} that will be checked whenever an
585     * activity is started.  The monitor is added
586     * after any existing ones; the monitor will be hit only if none of the
587     * existing monitors can themselves handle the Intent.
588     *
589     * @param monitor The new ActivityMonitor to see.
590     *
591     * @see #addMonitor(IntentFilter, ActivityResult, boolean)
592     * @see #checkMonitorHit
593     */
594    public void addMonitor(ActivityMonitor monitor) {
595        synchronized (mSync) {
596            if (mActivityMonitors == null) {
597                mActivityMonitors = new ArrayList();
598            }
599            mActivityMonitors.add(monitor);
600        }
601    }
602
603    /**
604     * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that
605     * creates an intent filter matching {@link ActivityMonitor} for you and
606     * returns it.
607     *
608     * @param filter The set of intents this monitor is responsible for.
609     * @param result A canned result to return if the monitor is hit; can
610     *               be null.
611     * @param block Controls whether the monitor should block the activity
612     *              start (returning its canned result) or let the call
613     *              proceed.
614     *
615     * @return The newly created and added activity monitor.
616     *
617     * @see #addMonitor(ActivityMonitor)
618     * @see #checkMonitorHit
619     */
620    public ActivityMonitor addMonitor(
621        IntentFilter filter, ActivityResult result, boolean block) {
622        ActivityMonitor am = new ActivityMonitor(filter, result, block);
623        addMonitor(am);
624        return am;
625    }
626
627    /**
628     * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that
629     * creates a class matching {@link ActivityMonitor} for you and returns it.
630     *
631     * @param cls The activity class this monitor is responsible for.
632     * @param result A canned result to return if the monitor is hit; can
633     *               be null.
634     * @param block Controls whether the monitor should block the activity
635     *              start (returning its canned result) or let the call
636     *              proceed.
637     *
638     * @return The newly created and added activity monitor.
639     *
640     * @see #addMonitor(ActivityMonitor)
641     * @see #checkMonitorHit
642     */
643    public ActivityMonitor addMonitor(
644        String cls, ActivityResult result, boolean block) {
645        ActivityMonitor am = new ActivityMonitor(cls, result, block);
646        addMonitor(am);
647        return am;
648    }
649
650    /**
651     * Test whether an existing {@link ActivityMonitor} has been hit.  If the
652     * monitor has been hit at least <var>minHits</var> times, then it will be
653     * removed from the activity monitor list and true returned.  Otherwise it
654     * is left as-is and false is returned.
655     *
656     * @param monitor The ActivityMonitor to check.
657     * @param minHits The minimum number of hits required.
658     *
659     * @return True if the hit count has been reached, else false.
660     *
661     * @see #addMonitor
662     */
663    public boolean checkMonitorHit(ActivityMonitor monitor, int minHits) {
664        waitForIdleSync();
665        synchronized (mSync) {
666            if (monitor.getHits() < minHits) {
667                return false;
668            }
669            mActivityMonitors.remove(monitor);
670        }
671        return true;
672    }
673
674    /**
675     * Wait for an existing {@link ActivityMonitor} to be hit.  Once the
676     * monitor has been hit, it is removed from the activity monitor list and
677     * the first created Activity object that matched it is returned.
678     *
679     * @param monitor The ActivityMonitor to wait for.
680     *
681     * @return The Activity object that matched the monitor.
682     */
683    public Activity waitForMonitor(ActivityMonitor monitor) {
684        Activity activity = monitor.waitForActivity();
685        synchronized (mSync) {
686            mActivityMonitors.remove(monitor);
687        }
688        return activity;
689    }
690
691    /**
692     * Wait for an existing {@link ActivityMonitor} to be hit till the timeout
693     * expires.  Once the monitor has been hit, it is removed from the activity
694     * monitor list and the first created Activity object that matched it is
695     * returned.  If the timeout expires, a null object is returned.
696     *
697     * @param monitor The ActivityMonitor to wait for.
698     * @param timeOut The timeout value in secs.
699     *
700     * @return The Activity object that matched the monitor.
701     */
702    public Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) {
703        Activity activity = monitor.waitForActivityWithTimeout(timeOut);
704        synchronized (mSync) {
705            mActivityMonitors.remove(monitor);
706        }
707        return activity;
708    }
709
710    /**
711     * Remove an {@link ActivityMonitor} that was previously added with
712     * {@link #addMonitor}.
713     *
714     * @param monitor The monitor to remove.
715     *
716     * @see #addMonitor
717     */
718    public void removeMonitor(ActivityMonitor monitor) {
719        synchronized (mSync) {
720            mActivityMonitors.remove(monitor);
721        }
722    }
723
724    /**
725     * Execute a particular menu item.
726     *
727     * @param targetActivity The activity in question.
728     * @param id The identifier associated with the menu item.
729     * @param flag Additional flags, if any.
730     * @return Whether the invocation was successful (for example, it could be
731     *         false if item is disabled).
732     */
733    public boolean invokeMenuActionSync(Activity targetActivity,
734                                    int id, int flag) {
735        class MenuRunnable implements Runnable {
736            private final Activity activity;
737            private final int identifier;
738            private final int flags;
739            boolean returnValue;
740
741            public MenuRunnable(Activity _activity, int _identifier,
742                                    int _flags) {
743                activity = _activity;
744                identifier = _identifier;
745                flags = _flags;
746            }
747
748            public void run() {
749                Window win = activity.getWindow();
750
751                returnValue = win.performPanelIdentifierAction(
752                            Window.FEATURE_OPTIONS_PANEL,
753                            identifier,
754                            flags);
755            }
756
757        }
758        MenuRunnable mr = new MenuRunnable(targetActivity, id, flag);
759        runOnMainSync(mr);
760        return mr.returnValue;
761    }
762
763    /**
764     * Show the context menu for the currently focused view and executes a
765     * particular context menu item.
766     *
767     * @param targetActivity The activity in question.
768     * @param id The identifier associated with the context menu item.
769     * @param flag Additional flags, if any.
770     * @return Whether the invocation was successful (for example, it could be
771     *         false if item is disabled).
772     */
773    public boolean invokeContextMenuAction(Activity targetActivity, int id, int flag) {
774        validateNotAppThread();
775
776        // Bring up context menu for current focus.
777        // It'd be nice to do this through code, but currently ListView depends on
778        //   long press to set metadata for its selected child
779
780        final KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
781        sendKeySync(downEvent);
782
783        // Need to wait for long press
784        waitForIdleSync();
785        try {
786            Thread.sleep(ViewConfiguration.getLongPressTimeout());
787        } catch (InterruptedException e) {
788            Log.e(TAG, "Could not sleep for long press timeout", e);
789            return false;
790        }
791
792        final KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER);
793        sendKeySync(upEvent);
794
795        // Wait for context menu to appear
796        waitForIdleSync();
797
798        class ContextMenuRunnable implements Runnable {
799            private final Activity activity;
800            private final int identifier;
801            private final int flags;
802            boolean returnValue;
803
804            public ContextMenuRunnable(Activity _activity, int _identifier,
805                                    int _flags) {
806                activity = _activity;
807                identifier = _identifier;
808                flags = _flags;
809            }
810
811            public void run() {
812                Window win = activity.getWindow();
813                returnValue = win.performContextMenuIdentifierAction(
814                            identifier,
815                            flags);
816            }
817
818        }
819
820        ContextMenuRunnable cmr = new ContextMenuRunnable(targetActivity, id, flag);
821        runOnMainSync(cmr);
822        return cmr.returnValue;
823    }
824
825    /**
826     * Sends the key events corresponding to the text to the app being
827     * instrumented.
828     *
829     * @param text The text to be sent.
830     */
831    public void sendStringSync(String text) {
832        if (text == null) {
833            return;
834        }
835        KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
836
837        KeyEvent[] events = keyCharacterMap.getEvents(text.toCharArray());
838
839        if (events != null) {
840            for (int i = 0; i < events.length; i++) {
841                // We have to change the time of an event before injecting it because
842                // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
843                // time stamp and the system rejects too old events. Hence, it is
844                // possible for an event to become stale before it is injected if it
845                // takes too long to inject the preceding ones.
846                sendKeySync(KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(), 0));
847            }
848        }
849    }
850
851    /**
852     * Send a key event to the currently focused window/view and wait for it to
853     * be processed.  Finished at some point after the recipient has returned
854     * from its event processing, though it may <em>not</em> have completely
855     * finished reacting from the event -- for example, if it needs to update
856     * its display as a result, it may still be in the process of doing that.
857     *
858     * @param event The event to send to the current focus.
859     */
860    public void sendKeySync(KeyEvent event) {
861        validateNotAppThread();
862        try {
863            (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
864                .injectKeyEvent(event, true);
865        } catch (RemoteException e) {
866        }
867    }
868
869    /**
870     * Sends an up and down key event sync to the currently focused window.
871     *
872     * @param key The integer keycode for the event.
873     */
874    public void sendKeyDownUpSync(int key) {
875        sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, key));
876        sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, key));
877    }
878
879    /**
880     * Higher-level method for sending both the down and up key events for a
881     * particular character key code.  Equivalent to creating both KeyEvent
882     * objects by hand and calling {@link #sendKeySync}.  The event appears
883     * as if it came from keyboard 0, the built in one.
884     *
885     * @param keyCode The key code of the character to send.
886     */
887    public void sendCharacterSync(int keyCode) {
888        sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
889        sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
890    }
891
892    /**
893     * Dispatch a pointer event. Finished at some point after the recipient has
894     * returned from its event processing, though it may <em>not</em> have
895     * completely finished reacting from the event -- for example, if it needs
896     * to update its display as a result, it may still be in the process of
897     * doing that.
898     *
899     * @param event A motion event describing the pointer action.  (As noted in
900     * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
901     * {@link SystemClock#uptimeMillis()} as the timebase.
902     */
903    public void sendPointerSync(MotionEvent event) {
904        validateNotAppThread();
905        try {
906            (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
907                .injectPointerEvent(event, true);
908        } catch (RemoteException e) {
909        }
910    }
911
912    /**
913     * Dispatch a trackball event. Finished at some point after the recipient has
914     * returned from its event processing, though it may <em>not</em> have
915     * completely finished reacting from the event -- for example, if it needs
916     * to update its display as a result, it may still be in the process of
917     * doing that.
918     *
919     * @param event A motion event describing the trackball action.  (As noted in
920     * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
921     * {@link SystemClock#uptimeMillis()} as the timebase.
922     */
923    public void sendTrackballEventSync(MotionEvent event) {
924        validateNotAppThread();
925        try {
926            (IWindowManager.Stub.asInterface(ServiceManager.getService("window")))
927                .injectTrackballEvent(event, true);
928        } catch (RemoteException e) {
929        }
930    }
931
932    /**
933     * Perform instantiation of the process's {@link Application} object.  The
934     * default implementation provides the normal system behavior.
935     *
936     * @param cl The ClassLoader with which to instantiate the object.
937     * @param className The name of the class implementing the Application
938     *                  object.
939     * @param context The context to initialize the application with
940     *
941     * @return The newly instantiated Application object.
942     */
943    public Application newApplication(ClassLoader cl, String className, Context context)
944            throws InstantiationException, IllegalAccessException,
945            ClassNotFoundException {
946        return newApplication(cl.loadClass(className), context);
947    }
948
949    /**
950     * Perform instantiation of the process's {@link Application} object.  The
951     * default implementation provides the normal system behavior.
952     *
953     * @param clazz The class used to create an Application object from.
954     * @param context The context to initialize the application with
955     *
956     * @return The newly instantiated Application object.
957     */
958    static public Application newApplication(Class<?> clazz, Context context)
959            throws InstantiationException, IllegalAccessException,
960            ClassNotFoundException {
961        Application app = (Application)clazz.newInstance();
962        app.attach(context);
963        return app;
964    }
965
966    /**
967     * Perform calling of the application's {@link Application#onCreate}
968     * method.  The default implementation simply calls through to that method.
969     *
970     * @param app The application being created.
971     */
972    public void callApplicationOnCreate(Application app) {
973        app.onCreate();
974    }
975
976    /**
977     * Perform instantiation of an {@link Activity} object.  This method is intended for use with
978     * unit tests, such as android.test.ActivityUnitTestCase.  The activity will be useable
979     * locally but will be missing some of the linkages necessary for use within the sytem.
980     *
981     * @param clazz The Class of the desired Activity
982     * @param context The base context for the activity to use
983     * @param token The token for this activity to communicate with
984     * @param application The application object (if any)
985     * @param intent The intent that started this Activity
986     * @param info ActivityInfo from the manifest
987     * @param title The title, typically retrieved from the ActivityInfo record
988     * @param parent The parent Activity (if any)
989     * @param id The embedded Id (if any)
990     * @param lastNonConfigurationInstance Arbitrary object that will be
991     * available via {@link Activity#getLastNonConfigurationInstance()
992     * Activity.getLastNonConfigurationInstance()}.
993     * @return Returns the instantiated activity
994     * @throws InstantiationException
995     * @throws IllegalAccessException
996     */
997    public Activity newActivity(Class<?> clazz, Context context,
998            IBinder token, Application application, Intent intent, ActivityInfo info,
999            CharSequence title, Activity parent, String id,
1000            Object lastNonConfigurationInstance) throws InstantiationException,
1001            IllegalAccessException {
1002        Activity activity = (Activity)clazz.newInstance();
1003        ActivityThread aThread = null;
1004        activity.attach(context, aThread, this, token, application, intent,
1005                info, title, parent, id,
1006                (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
1007                new Configuration());
1008        return activity;
1009    }
1010
1011    /**
1012     * Perform instantiation of the process's {@link Activity} object.  The
1013     * default implementation provides the normal system behavior.
1014     *
1015     * @param cl The ClassLoader with which to instantiate the object.
1016     * @param className The name of the class implementing the Activity
1017     *                  object.
1018     * @param intent The Intent object that specified the activity class being
1019     *               instantiated.
1020     *
1021     * @return The newly instantiated Activity object.
1022     */
1023    public Activity newActivity(ClassLoader cl, String className,
1024            Intent intent)
1025            throws InstantiationException, IllegalAccessException,
1026            ClassNotFoundException {
1027        return (Activity)cl.loadClass(className).newInstance();
1028    }
1029
1030    /**
1031     * Perform calling of an activity's {@link Activity#onCreate}
1032     * method.  The default implementation simply calls through to that method.
1033     *
1034     * @param activity The activity being created.
1035     * @param icicle The previously frozen state (or null) to pass through to
1036     *               onCreate().
1037     */
1038    public void callActivityOnCreate(Activity activity, Bundle icicle) {
1039        if (mWaitingActivities != null) {
1040            synchronized (mSync) {
1041                final int N = mWaitingActivities.size();
1042                for (int i=0; i<N; i++) {
1043                    final ActivityWaiter aw = mWaitingActivities.get(i);
1044                    final Intent intent = aw.intent;
1045                    if (intent.filterEquals(activity.getIntent())) {
1046                        aw.activity = activity;
1047                        mMessageQueue.addIdleHandler(new ActivityGoing(aw));
1048                    }
1049                }
1050            }
1051        }
1052
1053        activity.performCreate(icicle);
1054
1055        if (mActivityMonitors != null) {
1056            synchronized (mSync) {
1057                final int N = mActivityMonitors.size();
1058                for (int i=0; i<N; i++) {
1059                    final ActivityMonitor am = mActivityMonitors.get(i);
1060                    am.match(activity, activity, activity.getIntent());
1061                }
1062            }
1063        }
1064    }
1065
1066    public void callActivityOnDestroy(Activity activity) {
1067      // TODO: the following block causes intermittent hangs when using startActivity
1068      // temporarily comment out until root cause is fixed (bug 2630683)
1069//      if (mWaitingActivities != null) {
1070//          synchronized (mSync) {
1071//              final int N = mWaitingActivities.size();
1072//              for (int i=0; i<N; i++) {
1073//                  final ActivityWaiter aw = mWaitingActivities.get(i);
1074//                  final Intent intent = aw.intent;
1075//                  if (intent.filterEquals(activity.getIntent())) {
1076//                      aw.activity = activity;
1077//                      mMessageQueue.addIdleHandler(new ActivityGoing(aw));
1078//                  }
1079//              }
1080//          }
1081//      }
1082
1083      activity.performDestroy();
1084
1085      if (mActivityMonitors != null) {
1086          synchronized (mSync) {
1087              final int N = mActivityMonitors.size();
1088              for (int i=0; i<N; i++) {
1089                  final ActivityMonitor am = mActivityMonitors.get(i);
1090                  am.match(activity, activity, activity.getIntent());
1091              }
1092          }
1093      }
1094  }
1095
1096    /**
1097     * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
1098     * method.  The default implementation simply calls through to that method.
1099     *
1100     * @param activity The activity being restored.
1101     * @param savedInstanceState The previously saved state being restored.
1102     */
1103    public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
1104        activity.performRestoreInstanceState(savedInstanceState);
1105    }
1106
1107    /**
1108     * Perform calling of an activity's {@link Activity#onPostCreate} method.
1109     * The default implementation simply calls through to that method.
1110     *
1111     * @param activity The activity being created.
1112     * @param icicle The previously frozen state (or null) to pass through to
1113     *               onPostCreate().
1114     */
1115    public void callActivityOnPostCreate(Activity activity, Bundle icicle) {
1116        activity.onPostCreate(icicle);
1117    }
1118
1119    /**
1120     * Perform calling of an activity's {@link Activity#onNewIntent}
1121     * method.  The default implementation simply calls through to that method.
1122     *
1123     * @param activity The activity receiving a new Intent.
1124     * @param intent The new intent being received.
1125     */
1126    public void callActivityOnNewIntent(Activity activity, Intent intent) {
1127        activity.onNewIntent(intent);
1128    }
1129
1130    /**
1131     * Perform calling of an activity's {@link Activity#onStart}
1132     * method.  The default implementation simply calls through to that method.
1133     *
1134     * @param activity The activity being started.
1135     */
1136    public void callActivityOnStart(Activity activity) {
1137        activity.onStart();
1138    }
1139
1140    /**
1141     * Perform calling of an activity's {@link Activity#onRestart}
1142     * method.  The default implementation simply calls through to that method.
1143     *
1144     * @param activity The activity being restarted.
1145     */
1146    public void callActivityOnRestart(Activity activity) {
1147        activity.onRestart();
1148    }
1149
1150    /**
1151     * Perform calling of an activity's {@link Activity#onResume} method.  The
1152     * default implementation simply calls through to that method.
1153     *
1154     * @param activity The activity being resumed.
1155     */
1156    public void callActivityOnResume(Activity activity) {
1157        activity.mResumed = true;
1158        activity.onResume();
1159
1160        if (mActivityMonitors != null) {
1161            synchronized (mSync) {
1162                final int N = mActivityMonitors.size();
1163                for (int i=0; i<N; i++) {
1164                    final ActivityMonitor am = mActivityMonitors.get(i);
1165                    am.match(activity, activity, activity.getIntent());
1166                }
1167            }
1168        }
1169    }
1170
1171    /**
1172     * Perform calling of an activity's {@link Activity#onStop}
1173     * method.  The default implementation simply calls through to that method.
1174     *
1175     * @param activity The activity being stopped.
1176     */
1177    public void callActivityOnStop(Activity activity) {
1178        activity.onStop();
1179    }
1180
1181    /**
1182     * Perform calling of an activity's {@link Activity#onPause} method.  The
1183     * default implementation simply calls through to that method.
1184     *
1185     * @param activity The activity being saved.
1186     * @param outState The bundle to pass to the call.
1187     */
1188    public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
1189        activity.performSaveInstanceState(outState);
1190    }
1191
1192    /**
1193     * Perform calling of an activity's {@link Activity#onPause} method.  The
1194     * default implementation simply calls through to that method.
1195     *
1196     * @param activity The activity being paused.
1197     */
1198    public void callActivityOnPause(Activity activity) {
1199        activity.performPause();
1200    }
1201
1202    /**
1203     * Perform calling of an activity's {@link Activity#onUserLeaveHint} method.
1204     * The default implementation simply calls through to that method.
1205     *
1206     * @param activity The activity being notified that the user has navigated away
1207     */
1208    public void callActivityOnUserLeaving(Activity activity) {
1209        activity.performUserLeaving();
1210    }
1211
1212    /*
1213     * Starts allocation counting. This triggers a gc and resets the counts.
1214     */
1215    public void startAllocCounting() {
1216        // Before we start trigger a GC and reset the debug counts. Run the
1217        // finalizers and another GC before starting and stopping the alloc
1218        // counts. This will free up any objects that were just sitting around
1219        // waiting for their finalizers to be run.
1220        Runtime.getRuntime().gc();
1221        Runtime.getRuntime().runFinalization();
1222        Runtime.getRuntime().gc();
1223
1224        Debug.resetAllCounts();
1225
1226        // start the counts
1227        Debug.startAllocCounting();
1228    }
1229
1230    /*
1231     * Stops allocation counting.
1232     */
1233    public void stopAllocCounting() {
1234        Runtime.getRuntime().gc();
1235        Runtime.getRuntime().runFinalization();
1236        Runtime.getRuntime().gc();
1237        Debug.stopAllocCounting();
1238    }
1239
1240    /**
1241     * If Results already contains Key, it appends Value to the key's ArrayList
1242     * associated with the key. If the key doesn't already exist in results, it
1243     * adds the key/value pair to results.
1244     */
1245    private void addValue(String key, int value, Bundle results) {
1246        if (results.containsKey(key)) {
1247            List<Integer> list = results.getIntegerArrayList(key);
1248            if (list != null) {
1249                list.add(value);
1250            }
1251        } else {
1252            ArrayList<Integer> list = new ArrayList<Integer>();
1253            list.add(value);
1254            results.putIntegerArrayList(key, list);
1255        }
1256    }
1257
1258    /**
1259     * Returns a bundle with the current results from the allocation counting.
1260     */
1261    public Bundle getAllocCounts() {
1262        Bundle results = new Bundle();
1263        results.putLong("global_alloc_count", Debug.getGlobalAllocCount());
1264        results.putLong("global_alloc_size", Debug.getGlobalAllocSize());
1265        results.putLong("global_freed_count", Debug.getGlobalFreedCount());
1266        results.putLong("global_freed_size", Debug.getGlobalFreedSize());
1267        results.putLong("gc_invocation_count", Debug.getGlobalGcInvocationCount());
1268        return results;
1269    }
1270
1271    /**
1272     * Returns a bundle with the counts for various binder counts for this process. Currently the only two that are
1273     * reported are the number of send and the number of received transactions.
1274     */
1275    public Bundle getBinderCounts() {
1276        Bundle results = new Bundle();
1277        results.putLong("sent_transactions", Debug.getBinderSentTransactions());
1278        results.putLong("received_transactions", Debug.getBinderReceivedTransactions());
1279        return results;
1280    }
1281
1282    /**
1283     * Description of a Activity execution result to return to the original
1284     * activity.
1285     */
1286    public static final class ActivityResult {
1287        /**
1288         * Create a new activity result.  See {@link Activity#setResult} for
1289         * more information.
1290         *
1291         * @param resultCode The result code to propagate back to the
1292         * originating activity, often RESULT_CANCELED or RESULT_OK
1293         * @param resultData The data to propagate back to the originating
1294         * activity.
1295         */
1296        public ActivityResult(int resultCode, Intent resultData) {
1297            mResultCode = resultCode;
1298            mResultData = resultData;
1299        }
1300
1301        /**
1302         * Retrieve the result code contained in this result.
1303         */
1304        public int getResultCode() {
1305            return mResultCode;
1306        }
1307
1308        /**
1309         * Retrieve the data contained in this result.
1310         */
1311        public Intent getResultData() {
1312            return mResultData;
1313        }
1314
1315        private final int mResultCode;
1316        private final Intent mResultData;
1317    }
1318
1319    /**
1320     * Execute a startActivity call made by the application.  The default
1321     * implementation takes care of updating any active {@link ActivityMonitor}
1322     * objects and dispatches this call to the system activity manager; you can
1323     * override this to watch for the application to start an activity, and
1324     * modify what happens when it does.
1325     *
1326     * <p>This method returns an {@link ActivityResult} object, which you can
1327     * use when intercepting application calls to avoid performing the start
1328     * activity action but still return the result the application is
1329     * expecting.  To do this, override this method to catch the call to start
1330     * activity so that it returns a new ActivityResult containing the results
1331     * you would like the application to see, and don't call up to the super
1332     * class.  Note that an application is only expecting a result if
1333     * <var>requestCode</var> is &gt;= 0.
1334     *
1335     * <p>This method throws {@link android.content.ActivityNotFoundException}
1336     * if there was no Activity found to run the given Intent.
1337     *
1338     * @param who The Context from which the activity is being started.
1339     * @param contextThread The main thread of the Context from which the activity
1340     *                      is being started.
1341     * @param token Internal token identifying to the system who is starting
1342     *              the activity; may be null.
1343     * @param target Which activity is performing the start (and thus receiving
1344     *               any result); may be null if this call is not being made
1345     *               from an activity.
1346     * @param intent The actual Intent to start.
1347     * @param requestCode Identifier for this request's result; less than zero
1348     *                    if the caller is not expecting a result.
1349     *
1350     * @return To force the return of a particular result, return an
1351     *         ActivityResult object containing the desired data; otherwise
1352     *         return null.  The default implementation always returns null.
1353     *
1354     * @throws android.content.ActivityNotFoundException
1355     *
1356     * @see Activity#startActivity(Intent)
1357     * @see Activity#startActivityForResult(Intent, int)
1358     * @see Activity#startActivityFromChild
1359     *
1360     * {@hide}
1361     */
1362    public ActivityResult execStartActivity(
1363            Context who, IBinder contextThread, IBinder token, Activity target,
1364            Intent intent, int requestCode) {
1365        IApplicationThread whoThread = (IApplicationThread) contextThread;
1366        if (mActivityMonitors != null) {
1367            synchronized (mSync) {
1368                final int N = mActivityMonitors.size();
1369                for (int i=0; i<N; i++) {
1370                    final ActivityMonitor am = mActivityMonitors.get(i);
1371                    if (am.match(who, null, intent)) {
1372                        am.mHits++;
1373                        if (am.isBlocking()) {
1374                            return requestCode >= 0 ? am.getResult() : null;
1375                        }
1376                        break;
1377                    }
1378                }
1379            }
1380        }
1381        try {
1382            intent.setAllowFds(false);
1383            int result = ActivityManagerNative.getDefault()
1384                .startActivity(whoThread, intent,
1385                        intent.resolveTypeIfNeeded(who.getContentResolver()),
1386                        null, 0, token, target != null ? target.mEmbeddedID : null,
1387                        requestCode, false, false, false, null, null, false);
1388            checkStartActivityResult(result, intent);
1389        } catch (RemoteException e) {
1390        }
1391        return null;
1392    }
1393
1394    /**
1395     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
1396     * but accepts an array of activities to be started.  Note that active
1397     * {@link ActivityMonitor} objects only match against the first activity in
1398     * the array.
1399     *
1400     * {@hide}
1401     */
1402    public void execStartActivities(Context who, IBinder contextThread,
1403            IBinder token, Activity target, Intent[] intents) {
1404        IApplicationThread whoThread = (IApplicationThread) contextThread;
1405        if (mActivityMonitors != null) {
1406            synchronized (mSync) {
1407                final int N = mActivityMonitors.size();
1408                for (int i=0; i<N; i++) {
1409                    final ActivityMonitor am = mActivityMonitors.get(i);
1410                    if (am.match(who, null, intents[0])) {
1411                        am.mHits++;
1412                        if (am.isBlocking()) {
1413                            return;
1414                        }
1415                        break;
1416                    }
1417                }
1418            }
1419        }
1420        try {
1421            String[] resolvedTypes = new String[intents.length];
1422            for (int i=0; i<intents.length; i++) {
1423                intents[i].setAllowFds(false);
1424                resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
1425            }
1426            int result = ActivityManagerNative.getDefault()
1427                .startActivities(whoThread, intents, resolvedTypes, token);
1428            checkStartActivityResult(result, intents[0]);
1429        } catch (RemoteException e) {
1430        }
1431    }
1432
1433    /**
1434     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
1435     * but for calls from a {#link Fragment}.
1436     *
1437     * @param who The Context from which the activity is being started.
1438     * @param contextThread The main thread of the Context from which the activity
1439     *                      is being started.
1440     * @param token Internal token identifying to the system who is starting
1441     *              the activity; may be null.
1442     * @param target Which fragment is performing the start (and thus receiving
1443     *               any result).
1444     * @param intent The actual Intent to start.
1445     * @param requestCode Identifier for this request's result; less than zero
1446     *                    if the caller is not expecting a result.
1447     *
1448     * @return To force the return of a particular result, return an
1449     *         ActivityResult object containing the desired data; otherwise
1450     *         return null.  The default implementation always returns null.
1451     *
1452     * @throws android.content.ActivityNotFoundException
1453     *
1454     * @see Activity#startActivity(Intent)
1455     * @see Activity#startActivityForResult(Intent, int)
1456     * @see Activity#startActivityFromChild
1457     *
1458     * {@hide}
1459     */
1460    public ActivityResult execStartActivity(
1461        Context who, IBinder contextThread, IBinder token, Fragment target,
1462        Intent intent, int requestCode) {
1463        IApplicationThread whoThread = (IApplicationThread) contextThread;
1464        if (mActivityMonitors != null) {
1465            synchronized (mSync) {
1466                final int N = mActivityMonitors.size();
1467                for (int i=0; i<N; i++) {
1468                    final ActivityMonitor am = mActivityMonitors.get(i);
1469                    if (am.match(who, null, intent)) {
1470                        am.mHits++;
1471                        if (am.isBlocking()) {
1472                            return requestCode >= 0 ? am.getResult() : null;
1473                        }
1474                        break;
1475                    }
1476                }
1477            }
1478        }
1479        try {
1480            intent.setAllowFds(false);
1481            int result = ActivityManagerNative.getDefault()
1482                .startActivity(whoThread, intent,
1483                        intent.resolveTypeIfNeeded(who.getContentResolver()),
1484                        null, 0, token, target != null ? target.mWho : null,
1485                        requestCode, false, false /* debug */, false /* openglTrace */,
1486                        null, null, false);
1487            checkStartActivityResult(result, intent);
1488        } catch (RemoteException e) {
1489        }
1490        return null;
1491    }
1492
1493    /*package*/ final void init(ActivityThread thread,
1494            Context instrContext, Context appContext, ComponentName component,
1495            IInstrumentationWatcher watcher) {
1496        mThread = thread;
1497        mMessageQueue = mThread.getLooper().myQueue();
1498        mInstrContext = instrContext;
1499        mAppContext = appContext;
1500        mComponent = component;
1501        mWatcher = watcher;
1502    }
1503
1504    /*package*/ static void checkStartActivityResult(int res, Object intent) {
1505        if (res >= IActivityManager.START_SUCCESS) {
1506            return;
1507        }
1508
1509        switch (res) {
1510            case IActivityManager.START_INTENT_NOT_RESOLVED:
1511            case IActivityManager.START_CLASS_NOT_FOUND:
1512                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
1513                    throw new ActivityNotFoundException(
1514                            "Unable to find explicit activity class "
1515                            + ((Intent)intent).getComponent().toShortString()
1516                            + "; have you declared this activity in your AndroidManifest.xml?");
1517                throw new ActivityNotFoundException(
1518                        "No Activity found to handle " + intent);
1519            case IActivityManager.START_PERMISSION_DENIED:
1520                throw new SecurityException("Not allowed to start activity "
1521                        + intent);
1522            case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
1523                throw new AndroidRuntimeException(
1524                        "FORWARD_RESULT_FLAG used while also requesting a result");
1525            case IActivityManager.START_NOT_ACTIVITY:
1526                throw new IllegalArgumentException(
1527                        "PendingIntent is not an activity");
1528            default:
1529                throw new AndroidRuntimeException("Unknown error code "
1530                        + res + " when starting " + intent);
1531        }
1532    }
1533
1534    private final void validateNotAppThread() {
1535        if (ActivityThread.currentActivityThread() != null) {
1536            throw new RuntimeException(
1537                "This method can not be called from the main application thread");
1538        }
1539    }
1540
1541    private final class InstrumentationThread extends Thread {
1542        public InstrumentationThread(String name) {
1543            super(name);
1544        }
1545        public void run() {
1546            IActivityManager am = ActivityManagerNative.getDefault();
1547            try {
1548                Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
1549            } catch (RuntimeException e) {
1550                Log.w(TAG, "Exception setting priority of instrumentation thread "
1551                        + Process.myTid(), e);
1552            }
1553            if (mAutomaticPerformanceSnapshots) {
1554                startPerformanceSnapshot();
1555            }
1556            onStart();
1557        }
1558    }
1559
1560    private static final class EmptyRunnable implements Runnable {
1561        public void run() {
1562        }
1563    }
1564
1565    private static final class SyncRunnable implements Runnable {
1566        private final Runnable mTarget;
1567        private boolean mComplete;
1568
1569        public SyncRunnable(Runnable target) {
1570            mTarget = target;
1571        }
1572
1573        public void run() {
1574            mTarget.run();
1575            synchronized (this) {
1576                mComplete = true;
1577                notifyAll();
1578            }
1579        }
1580
1581        public void waitForComplete() {
1582            synchronized (this) {
1583                while (!mComplete) {
1584                    try {
1585                        wait();
1586                    } catch (InterruptedException e) {
1587                    }
1588                }
1589            }
1590        }
1591    }
1592
1593    private static final class ActivityWaiter {
1594        public final Intent intent;
1595        public Activity activity;
1596
1597        public ActivityWaiter(Intent _intent) {
1598            intent = _intent;
1599        }
1600    }
1601
1602    private final class ActivityGoing implements MessageQueue.IdleHandler {
1603        private final ActivityWaiter mWaiter;
1604
1605        public ActivityGoing(ActivityWaiter waiter) {
1606            mWaiter = waiter;
1607        }
1608
1609        public final boolean queueIdle() {
1610            synchronized (mSync) {
1611                mWaitingActivities.remove(mWaiter);
1612                mSync.notifyAll();
1613            }
1614            return false;
1615        }
1616    }
1617
1618    private static final class Idler implements MessageQueue.IdleHandler {
1619        private final Runnable mCallback;
1620        private boolean mIdle;
1621
1622        public Idler(Runnable callback) {
1623            mCallback = callback;
1624            mIdle = false;
1625        }
1626
1627        public final boolean queueIdle() {
1628            if (mCallback != null) {
1629                mCallback.run();
1630            }
1631            synchronized (this) {
1632                mIdle = true;
1633                notifyAll();
1634            }
1635            return false;
1636        }
1637
1638        public void waitForIdle() {
1639            synchronized (this) {
1640                while (!mIdle) {
1641                    try {
1642                        wait();
1643                    } catch (InterruptedException e) {
1644                    }
1645                }
1646            }
1647        }
1648    }
1649}
1650