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