blob: e58ccb81d4795967efac17f326cc8db8617bf537 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.app;
18
19import android.content.ActivityNotFoundException;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.ActivityInfo;
25import android.content.res.Configuration;
Jeff Brownac143512012-04-05 18:57:33 -070026import android.hardware.input.InputManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.os.Debug;
29import android.os.IBinder;
Kristian Monsen0a303282013-01-18 14:50:07 -080030import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.MessageQueue;
Svetoslav Ganovc350f162011-11-10 17:54:24 -080032import android.os.PerformanceCollector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.os.Process;
Svetoslav Ganovc350f162011-11-10 17:54:24 -080034import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.os.ServiceManager;
Svetoslav Ganovc350f162011-11-10 17:54:24 -080036import android.os.SystemClock;
Dianne Hackbornf1c26e22012-08-23 13:54:58 -070037import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.util.AndroidRuntimeException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.util.Log;
40import android.view.IWindowManager;
Jeff Brownac143512012-04-05 18:57:33 -070041import android.view.InputDevice;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.view.KeyCharacterMap;
43import android.view.KeyEvent;
44import android.view.MotionEvent;
45import android.view.ViewConfiguration;
46import android.view.Window;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
48import java.io.File;
49import java.util.ArrayList;
50import java.util.List;
51
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052/**
53 * Base class for implementing application instrumentation code. When running
54 * with instrumentation turned on, this class will be instantiated for you
55 * before any of the application code, allowing you to monitor all of the
56 * interaction the system has with the application. An Instrumentation
57 * implementation is described to the system through an AndroidManifest.xml's
58 * <instrumentation> tag.
59 */
60public class Instrumentation {
Svetoslav Ganov80943d82013-01-02 10:25:37 -080061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 /**
63 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
64 * identifies the class that is writing the report. This can be used to provide more structured
65 * logging or reporting capabilities in the IInstrumentationWatcher.
66 */
67 public static final String REPORT_KEY_IDENTIFIER = "id";
68 /**
69 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
70 * identifies a string which can simply be printed to the output stream. Using these streams
71 * provides a "pretty printer" version of the status & final packets. Any bundles including
72 * this key should also include the complete set of raw key/value pairs, so that the
73 * instrumentation can also be launched, and results collected, by an automated system.
74 */
75 public static final String REPORT_KEY_STREAMRESULT = "stream";
Svetoslav Ganov80943d82013-01-02 10:25:37 -080076
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 private static final String TAG = "Instrumentation";
78
79 private final Object mSync = new Object();
80 private ActivityThread mThread = null;
81 private MessageQueue mMessageQueue = null;
82 private Context mInstrContext;
83 private Context mAppContext;
84 private ComponentName mComponent;
85 private Thread mRunner;
86 private List<ActivityWaiter> mWaitingActivities;
87 private List<ActivityMonitor> mActivityMonitors;
88 private IInstrumentationWatcher mWatcher;
Svetoslav Ganov80943d82013-01-02 10:25:37 -080089 private IUiAutomationConnection mUiAutomationConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private boolean mAutomaticPerformanceSnapshots = false;
Jack Wangff1df692009-08-26 17:19:13 -070091 private PerformanceCollector mPerformanceCollector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 private Bundle mPerfMetrics = new Bundle();
Svetoslav Ganov80943d82013-01-02 10:25:37 -080093 private UiAutomation mUiAutomation;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094
95 public Instrumentation() {
96 }
97
98 /**
99 * Called when the instrumentation is starting, before any application code
100 * has been loaded. Usually this will be implemented to simply call
101 * {@link #start} to begin the instrumentation thread, which will then
102 * continue execution in {@link #onStart}.
103 *
104 * <p>If you do not need your own thread -- that is you are writing your
105 * instrumentation to be completely asynchronous (returning to the event
106 * loop so that the application can run), you can simply begin your
107 * instrumentation here, for example call {@link Context#startActivity} to
108 * begin the appropriate first activity of the application.
109 *
110 * @param arguments Any additional arguments that were supplied when the
111 * instrumentation was started.
112 */
113 public void onCreate(Bundle arguments) {
114 }
115
116 /**
117 * Create and start a new thread in which to run instrumentation. This new
118 * thread will call to {@link #onStart} where you can implement the
119 * instrumentation.
120 */
121 public void start() {
122 if (mRunner != null) {
123 throw new RuntimeException("Instrumentation already started");
124 }
125 mRunner = new InstrumentationThread("Instr: " + getClass().getName());
126 mRunner.start();
127 }
128
129 /**
130 * Method where the instrumentation thread enters execution. This allows
131 * you to run your instrumentation code in a separate thread than the
132 * application, so that it can perform blocking operation such as
133 * {@link #sendKeySync} or {@link #startActivitySync}.
134 *
135 * <p>You will typically want to call finish() when this function is done,
136 * to end your instrumentation.
137 */
138 public void onStart() {
139 }
140
141 /**
142 * This is called whenever the system captures an unhandled exception that
143 * was thrown by the application. The default implementation simply
144 * returns false, allowing normal system handling of the exception to take
145 * place.
146 *
147 * @param obj The client object that generated the exception. May be an
148 * Application, Activity, BroadcastReceiver, Service, or null.
149 * @param e The exception that was thrown.
150 *
151 * @return To allow normal system exception process to occur, return false.
152 * If true is returned, the system will proceed as if the exception
153 * didn't happen.
154 */
155 public boolean onException(Object obj, Throwable e) {
156 return false;
157 }
158
159 /**
160 * Provide a status report about the application.
161 *
162 * @param resultCode Current success/failure of instrumentation.
163 * @param results Any results to send back to the code that started the instrumentation.
164 */
165 public void sendStatus(int resultCode, Bundle results) {
166 if (mWatcher != null) {
167 try {
168 mWatcher.instrumentationStatus(mComponent, resultCode, results);
169 }
170 catch (RemoteException e) {
171 mWatcher = null;
172 }
173 }
174 }
175
176 /**
177 * Terminate instrumentation of the application. This will cause the
178 * application process to exit, removing this instrumentation from the next
179 * time the application is started.
180 *
181 * @param resultCode Overall success/failure of instrumentation.
182 * @param results Any results to send back to the code that started the
183 * instrumentation.
184 */
185 public void finish(int resultCode, Bundle results) {
186 if (mAutomaticPerformanceSnapshots) {
187 endPerformanceSnapshot();
188 }
189 if (mPerfMetrics != null) {
190 results.putAll(mPerfMetrics);
191 }
Adam Momtaz8f6f1f42013-04-10 12:42:58 -0700192 if (mUiAutomation != null) {
193 mUiAutomation.disconnect();
194 mUiAutomation = null;
195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 mThread.finishInstrumentation(resultCode, results);
197 }
198
199 public void setAutomaticPerformanceSnapshots() {
200 mAutomaticPerformanceSnapshots = true;
Jack Wangff1df692009-08-26 17:19:13 -0700201 mPerformanceCollector = new PerformanceCollector();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 }
203
204 public void startPerformanceSnapshot() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 if (!isProfiling()) {
Jack Wangff1df692009-08-26 17:19:13 -0700206 mPerformanceCollector.beginSnapshot(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 }
208 }
209
210 public void endPerformanceSnapshot() {
211 if (!isProfiling()) {
Jack Wangff1df692009-08-26 17:19:13 -0700212 mPerfMetrics = mPerformanceCollector.endSnapshot();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 }
214 }
215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 /**
217 * Called when the instrumented application is stopping, after all of the
218 * normal application cleanup has occurred.
219 */
220 public void onDestroy() {
221 }
222
223 /**
224 * Return the Context of this instrumentation's package. Note that this is
225 * often different than the Context of the application being
226 * instrumentated, since the instrumentation code often lives is a
227 * different package than that of the application it is running against.
228 * See {@link #getTargetContext} to retrieve a Context for the target
229 * application.
230 *
231 * @return The instrumentation's package context.
232 *
233 * @see #getTargetContext
234 */
235 public Context getContext() {
236 return mInstrContext;
237 }
238
239 /**
240 * Returns complete component name of this instrumentation.
241 *
242 * @return Returns the complete component name for this instrumentation.
243 */
244 public ComponentName getComponentName() {
245 return mComponent;
246 }
247
248 /**
249 * Return a Context for the target application being instrumented. Note
250 * that this is often different than the Context of the instrumentation
251 * code, since the instrumentation code often lives is a different package
252 * than that of the application it is running against. See
253 * {@link #getContext} to retrieve a Context for the instrumentation code.
254 *
255 * @return A Context in the target application.
256 *
257 * @see #getContext
258 */
259 public Context getTargetContext() {
260 return mAppContext;
261 }
262
263 /**
264 * Check whether this instrumentation was started with profiling enabled.
265 *
266 * @return Returns true if profiling was enabled when starting, else false.
267 */
268 public boolean isProfiling() {
269 return mThread.isProfiling();
270 }
271
272 /**
273 * This method will start profiling if isProfiling() returns true. You should
274 * only call this method if you set the handleProfiling attribute in the
275 * manifest file for this Instrumentation to true.
276 */
277 public void startProfiling() {
278 if (mThread.isProfiling()) {
279 File file = new File(mThread.getProfileFilePath());
280 file.getParentFile().mkdirs();
281 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
282 }
283 }
284
285 /**
286 * Stops profiling if isProfiling() returns true.
287 */
288 public void stopProfiling() {
289 if (mThread.isProfiling()) {
290 Debug.stopMethodTracing();
291 }
292 }
293
294 /**
295 * Force the global system in or out of touch mode. This can be used if
296 * your instrumentation relies on the UI being in one more or the other
297 * when it starts.
298 *
299 * @param inTouch Set to true to be in touch mode, false to be in
300 * focus mode.
301 */
302 public void setInTouchMode(boolean inTouch) {
303 try {
304 IWindowManager.Stub.asInterface(
305 ServiceManager.getService("window")).setInTouchMode(inTouch);
306 } catch (RemoteException e) {
307 // Shouldn't happen!
308 }
309 }
310
311 /**
312 * Schedule a callback for when the application's main thread goes idle
313 * (has no more events to process).
314 *
315 * @param recipient Called the next time the thread's message queue is
316 * idle.
317 */
318 public void waitForIdle(Runnable recipient) {
319 mMessageQueue.addIdleHandler(new Idler(recipient));
320 mThread.getHandler().post(new EmptyRunnable());
321 }
322
323 /**
324 * Synchronously wait for the application to be idle. Can not be called
325 * from the main application thread -- use {@link #start} to execute
326 * instrumentation in its own thread.
327 */
328 public void waitForIdleSync() {
329 validateNotAppThread();
330 Idler idler = new Idler(null);
331 mMessageQueue.addIdleHandler(idler);
332 mThread.getHandler().post(new EmptyRunnable());
333 idler.waitForIdle();
334 }
335
336 /**
337 * Execute a call on the application's main thread, blocking until it is
338 * complete. Useful for doing things that are not thread-safe, such as
339 * looking at or modifying the view hierarchy.
340 *
341 * @param runner The code to run on the main thread.
342 */
343 public void runOnMainSync(Runnable runner) {
344 validateNotAppThread();
345 SyncRunnable sr = new SyncRunnable(runner);
346 mThread.getHandler().post(sr);
347 sr.waitForComplete();
348 }
349
350 /**
351 * Start a new activity and wait for it to begin running before returning.
352 * In addition to being synchronous, this method as some semantic
353 * differences from the standard {@link Context#startActivity} call: the
354 * activity component is resolved before talking with the activity manager
355 * (its class name is specified in the Intent that this method ultimately
356 * starts), and it does not allow you to start activities that run in a
357 * different process. In addition, if the given Intent resolves to
358 * multiple activities, instead of displaying a dialog for the user to
359 * select an activity, an exception will be thrown.
360 *
361 * <p>The function returns as soon as the activity goes idle following the
362 * call to its {@link Activity#onCreate}. Generally this means it has gone
363 * through the full initialization including {@link Activity#onResume} and
364 * drawn and displayed its initial window.
365 *
366 * @param intent Description of the activity to start.
367 *
368 * @see Context#startActivity
369 */
370 public Activity startActivitySync(Intent intent) {
371 validateNotAppThread();
372
373 synchronized (mSync) {
374 intent = new Intent(intent);
375
376 ActivityInfo ai = intent.resolveActivityInfo(
377 getTargetContext().getPackageManager(), 0);
378 if (ai == null) {
379 throw new RuntimeException("Unable to resolve activity for: " + intent);
380 }
Dianne Hackbornd97c7ad2009-06-19 11:37:35 -0700381 String myProc = mThread.getProcessName();
382 if (!ai.processName.equals(myProc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 // todo: if this intent is ambiguous, look here to see if
384 // there is a single match that is in our package.
Dianne Hackbornd97c7ad2009-06-19 11:37:35 -0700385 throw new RuntimeException("Intent in process "
386 + myProc + " resolved to different process "
387 + ai.processName + ": " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 }
389
390 intent.setComponent(new ComponentName(
391 ai.applicationInfo.packageName, ai.name));
392 final ActivityWaiter aw = new ActivityWaiter(intent);
393
394 if (mWaitingActivities == null) {
395 mWaitingActivities = new ArrayList();
396 }
397 mWaitingActivities.add(aw);
398
399 getTargetContext().startActivity(intent);
400
401 do {
402 try {
403 mSync.wait();
404 } catch (InterruptedException e) {
405 }
406 } while (mWaitingActivities.contains(aw));
407
408 return aw.activity;
409 }
410 }
411
412 /**
413 * Information about a particular kind of Intent that is being monitored.
414 * An instance of this class is added to the
415 * current instrumentation through {@link #addMonitor}; after being added,
416 * when a new activity is being started the monitor will be checked and, if
417 * matching, its hit count updated and (optionally) the call stopped and a
418 * canned result returned.
419 *
420 * <p>An ActivityMonitor can also be used to look for the creation of an
421 * activity, through the {@link #waitForActivity} method. This will return
422 * after a matching activity has been created with that activity object.
423 */
424 public static class ActivityMonitor {
425 private final IntentFilter mWhich;
426 private final String mClass;
427 private final ActivityResult mResult;
428 private final boolean mBlock;
429
430
431 // This is protected by 'Instrumentation.this.mSync'.
432 /*package*/ int mHits = 0;
433
434 // This is protected by 'this'.
435 /*package*/ Activity mLastActivity = null;
436
437 /**
438 * Create a new ActivityMonitor that looks for a particular kind of
439 * intent to be started.
440 *
441 * @param which The set of intents this monitor is responsible for.
442 * @param result A canned result to return if the monitor is hit; can
443 * be null.
444 * @param block Controls whether the monitor should block the activity
445 * start (returning its canned result) or let the call
446 * proceed.
447 *
448 * @see Instrumentation#addMonitor
449 */
450 public ActivityMonitor(
451 IntentFilter which, ActivityResult result, boolean block) {
452 mWhich = which;
453 mClass = null;
454 mResult = result;
455 mBlock = block;
456 }
457
458 /**
459 * Create a new ActivityMonitor that looks for a specific activity
460 * class to be started.
461 *
462 * @param cls The activity class this monitor is responsible for.
463 * @param result A canned result to return if the monitor is hit; can
464 * be null.
465 * @param block Controls whether the monitor should block the activity
466 * start (returning its canned result) or let the call
467 * proceed.
468 *
469 * @see Instrumentation#addMonitor
470 */
471 public ActivityMonitor(
472 String cls, ActivityResult result, boolean block) {
473 mWhich = null;
474 mClass = cls;
475 mResult = result;
476 mBlock = block;
477 }
478
479 /**
480 * Retrieve the filter associated with this ActivityMonitor.
481 */
482 public final IntentFilter getFilter() {
483 return mWhich;
484 }
485
486 /**
487 * Retrieve the result associated with this ActivityMonitor, or null if
488 * none.
489 */
490 public final ActivityResult getResult() {
491 return mResult;
492 }
493
494 /**
495 * Check whether this monitor blocks activity starts (not allowing the
496 * actual activity to run) or allows them to execute normally.
497 */
498 public final boolean isBlocking() {
499 return mBlock;
500 }
501
502 /**
503 * Retrieve the number of times the monitor has been hit so far.
504 */
505 public final int getHits() {
506 return mHits;
507 }
508
509 /**
510 * Retrieve the most recent activity class that was seen by this
511 * monitor.
512 */
513 public final Activity getLastActivity() {
514 return mLastActivity;
515 }
516
517 /**
518 * Block until an Activity is created that matches this monitor,
519 * returning the resulting activity.
520 *
521 * @return Activity
522 */
523 public final Activity waitForActivity() {
524 synchronized (this) {
525 while (mLastActivity == null) {
526 try {
527 wait();
528 } catch (InterruptedException e) {
529 }
530 }
531 Activity res = mLastActivity;
532 mLastActivity = null;
533 return res;
534 }
535 }
536
537 /**
538 * Block until an Activity is created that matches this monitor,
539 * returning the resulting activity or till the timeOut period expires.
540 * If the timeOut expires before the activity is started, return null.
541 *
542 * @param timeOut Time to wait before the activity is created.
543 *
544 * @return Activity
545 */
546 public final Activity waitForActivityWithTimeout(long timeOut) {
547 synchronized (this) {
Costin Manolacheb0935342011-07-15 11:20:42 -0700548 if (mLastActivity == null) {
549 try {
550 wait(timeOut);
551 } catch (InterruptedException e) {
552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
554 if (mLastActivity == null) {
555 return null;
556 } else {
557 Activity res = mLastActivity;
558 mLastActivity = null;
559 return res;
560 }
561 }
562 }
563
564 final boolean match(Context who,
565 Activity activity,
566 Intent intent) {
567 synchronized (this) {
568 if (mWhich != null
569 && mWhich.match(who.getContentResolver(), intent,
570 true, "Instrumentation") < 0) {
571 return false;
572 }
573 if (mClass != null) {
574 String cls = null;
575 if (activity != null) {
576 cls = activity.getClass().getName();
577 } else if (intent.getComponent() != null) {
578 cls = intent.getComponent().getClassName();
579 }
580 if (cls == null || !mClass.equals(cls)) {
581 return false;
582 }
583 }
584 if (activity != null) {
585 mLastActivity = activity;
586 notifyAll();
587 }
588 return true;
589 }
590 }
591 }
592
593 /**
594 * Add a new {@link ActivityMonitor} that will be checked whenever an
595 * activity is started. The monitor is added
596 * after any existing ones; the monitor will be hit only if none of the
597 * existing monitors can themselves handle the Intent.
598 *
599 * @param monitor The new ActivityMonitor to see.
600 *
601 * @see #addMonitor(IntentFilter, ActivityResult, boolean)
602 * @see #checkMonitorHit
603 */
604 public void addMonitor(ActivityMonitor monitor) {
605 synchronized (mSync) {
606 if (mActivityMonitors == null) {
607 mActivityMonitors = new ArrayList();
608 }
609 mActivityMonitors.add(monitor);
610 }
611 }
612
613 /**
614 * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that
615 * creates an intent filter matching {@link ActivityMonitor} for you and
616 * returns it.
617 *
618 * @param filter The set of intents this monitor is responsible for.
619 * @param result A canned result to return if the monitor is hit; can
620 * be null.
621 * @param block Controls whether the monitor should block the activity
622 * start (returning its canned result) or let the call
623 * proceed.
624 *
625 * @return The newly created and added activity monitor.
626 *
627 * @see #addMonitor(ActivityMonitor)
628 * @see #checkMonitorHit
629 */
630 public ActivityMonitor addMonitor(
631 IntentFilter filter, ActivityResult result, boolean block) {
632 ActivityMonitor am = new ActivityMonitor(filter, result, block);
633 addMonitor(am);
634 return am;
635 }
636
637 /**
638 * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that
639 * creates a class matching {@link ActivityMonitor} for you and returns it.
640 *
641 * @param cls The activity class this monitor is responsible for.
642 * @param result A canned result to return if the monitor is hit; can
643 * be null.
644 * @param block Controls whether the monitor should block the activity
645 * start (returning its canned result) or let the call
646 * proceed.
647 *
648 * @return The newly created and added activity monitor.
649 *
650 * @see #addMonitor(ActivityMonitor)
651 * @see #checkMonitorHit
652 */
653 public ActivityMonitor addMonitor(
654 String cls, ActivityResult result, boolean block) {
655 ActivityMonitor am = new ActivityMonitor(cls, result, block);
656 addMonitor(am);
657 return am;
658 }
659
660 /**
661 * Test whether an existing {@link ActivityMonitor} has been hit. If the
662 * monitor has been hit at least <var>minHits</var> times, then it will be
663 * removed from the activity monitor list and true returned. Otherwise it
664 * is left as-is and false is returned.
665 *
666 * @param monitor The ActivityMonitor to check.
667 * @param minHits The minimum number of hits required.
668 *
669 * @return True if the hit count has been reached, else false.
670 *
671 * @see #addMonitor
672 */
673 public boolean checkMonitorHit(ActivityMonitor monitor, int minHits) {
674 waitForIdleSync();
675 synchronized (mSync) {
676 if (monitor.getHits() < minHits) {
677 return false;
678 }
679 mActivityMonitors.remove(monitor);
680 }
681 return true;
682 }
683
684 /**
685 * Wait for an existing {@link ActivityMonitor} to be hit. Once the
686 * monitor has been hit, it is removed from the activity monitor list and
687 * the first created Activity object that matched it is returned.
688 *
689 * @param monitor The ActivityMonitor to wait for.
690 *
691 * @return The Activity object that matched the monitor.
692 */
693 public Activity waitForMonitor(ActivityMonitor monitor) {
694 Activity activity = monitor.waitForActivity();
695 synchronized (mSync) {
696 mActivityMonitors.remove(monitor);
697 }
698 return activity;
699 }
700
701 /**
702 * Wait for an existing {@link ActivityMonitor} to be hit till the timeout
703 * expires. Once the monitor has been hit, it is removed from the activity
704 * monitor list and the first created Activity object that matched it is
705 * returned. If the timeout expires, a null object is returned.
706 *
707 * @param monitor The ActivityMonitor to wait for.
708 * @param timeOut The timeout value in secs.
709 *
710 * @return The Activity object that matched the monitor.
711 */
712 public Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) {
713 Activity activity = monitor.waitForActivityWithTimeout(timeOut);
714 synchronized (mSync) {
715 mActivityMonitors.remove(monitor);
716 }
717 return activity;
718 }
719
720 /**
721 * Remove an {@link ActivityMonitor} that was previously added with
722 * {@link #addMonitor}.
723 *
724 * @param monitor The monitor to remove.
725 *
726 * @see #addMonitor
727 */
728 public void removeMonitor(ActivityMonitor monitor) {
729 synchronized (mSync) {
730 mActivityMonitors.remove(monitor);
731 }
732 }
733
734 /**
735 * Execute a particular menu item.
736 *
737 * @param targetActivity The activity in question.
738 * @param id The identifier associated with the menu item.
739 * @param flag Additional flags, if any.
740 * @return Whether the invocation was successful (for example, it could be
741 * false if item is disabled).
742 */
743 public boolean invokeMenuActionSync(Activity targetActivity,
744 int id, int flag) {
745 class MenuRunnable implements Runnable {
746 private final Activity activity;
747 private final int identifier;
748 private final int flags;
749 boolean returnValue;
750
751 public MenuRunnable(Activity _activity, int _identifier,
752 int _flags) {
753 activity = _activity;
754 identifier = _identifier;
755 flags = _flags;
756 }
757
758 public void run() {
759 Window win = activity.getWindow();
760
761 returnValue = win.performPanelIdentifierAction(
762 Window.FEATURE_OPTIONS_PANEL,
763 identifier,
764 flags);
765 }
766
767 }
768 MenuRunnable mr = new MenuRunnable(targetActivity, id, flag);
769 runOnMainSync(mr);
770 return mr.returnValue;
771 }
772
773 /**
774 * Show the context menu for the currently focused view and executes a
775 * particular context menu item.
776 *
777 * @param targetActivity The activity in question.
778 * @param id The identifier associated with the context menu item.
779 * @param flag Additional flags, if any.
780 * @return Whether the invocation was successful (for example, it could be
781 * false if item is disabled).
782 */
783 public boolean invokeContextMenuAction(Activity targetActivity, int id, int flag) {
784 validateNotAppThread();
785
786 // Bring up context menu for current focus.
787 // It'd be nice to do this through code, but currently ListView depends on
788 // long press to set metadata for its selected child
789
790 final KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
791 sendKeySync(downEvent);
792
793 // Need to wait for long press
794 waitForIdleSync();
795 try {
796 Thread.sleep(ViewConfiguration.getLongPressTimeout());
797 } catch (InterruptedException e) {
798 Log.e(TAG, "Could not sleep for long press timeout", e);
799 return false;
800 }
801
802 final KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER);
803 sendKeySync(upEvent);
804
805 // Wait for context menu to appear
806 waitForIdleSync();
807
808 class ContextMenuRunnable implements Runnable {
809 private final Activity activity;
810 private final int identifier;
811 private final int flags;
812 boolean returnValue;
813
814 public ContextMenuRunnable(Activity _activity, int _identifier,
815 int _flags) {
816 activity = _activity;
817 identifier = _identifier;
818 flags = _flags;
819 }
820
821 public void run() {
822 Window win = activity.getWindow();
823 returnValue = win.performContextMenuIdentifierAction(
824 identifier,
825 flags);
826 }
827
828 }
829
830 ContextMenuRunnable cmr = new ContextMenuRunnable(targetActivity, id, flag);
831 runOnMainSync(cmr);
832 return cmr.returnValue;
833 }
834
835 /**
836 * Sends the key events corresponding to the text to the app being
837 * instrumented.
838 *
839 * @param text The text to be sent.
840 */
841 public void sendStringSync(String text) {
842 if (text == null) {
843 return;
844 }
Jeff Brown6b53e8d2010-11-10 16:03:06 -0800845 KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
Svetoslav Ganovc350f162011-11-10 17:54:24 -0800846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 KeyEvent[] events = keyCharacterMap.getEvents(text.toCharArray());
Svetoslav Ganovc350f162011-11-10 17:54:24 -0800848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 if (events != null) {
850 for (int i = 0; i < events.length; i++) {
Svetoslav Ganovf434e372011-11-11 16:50:21 -0800851 // We have to change the time of an event before injecting it because
852 // all KeyEvents returned by KeyCharacterMap.getEvents() have the same
853 // time stamp and the system rejects too old events. Hence, it is
854 // possible for an event to become stale before it is injected if it
855 // takes too long to inject the preceding ones.
Svetoslav Ganovc350f162011-11-10 17:54:24 -0800856 sendKeySync(KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(), 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 }
Svetoslav Ganovc350f162011-11-10 17:54:24 -0800858 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 }
Svetoslav Ganovc350f162011-11-10 17:54:24 -0800860
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 /**
862 * Send a key event to the currently focused window/view and wait for it to
863 * be processed. Finished at some point after the recipient has returned
864 * from its event processing, though it may <em>not</em> have completely
865 * finished reacting from the event -- for example, if it needs to update
866 * its display as a result, it may still be in the process of doing that.
867 *
868 * @param event The event to send to the current focus.
869 */
870 public void sendKeySync(KeyEvent event) {
871 validateNotAppThread();
Jeff Brownac143512012-04-05 18:57:33 -0700872
873 long downTime = event.getDownTime();
874 long eventTime = event.getEventTime();
875 int action = event.getAction();
876 int code = event.getKeyCode();
877 int repeatCount = event.getRepeatCount();
878 int metaState = event.getMetaState();
879 int deviceId = event.getDeviceId();
880 int scancode = event.getScanCode();
881 int source = event.getSource();
882 int flags = event.getFlags();
883 if (source == InputDevice.SOURCE_UNKNOWN) {
884 source = InputDevice.SOURCE_KEYBOARD;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 }
Jeff Brownac143512012-04-05 18:57:33 -0700886 if (eventTime == 0) {
887 eventTime = SystemClock.uptimeMillis();
888 }
889 if (downTime == 0) {
890 downTime = eventTime;
891 }
892 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
893 deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700894 InputManager.getInstance().injectInputEvent(newEvent,
Jeff Brownac143512012-04-05 18:57:33 -0700895 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 }
897
898 /**
899 * Sends an up and down key event sync to the currently focused window.
900 *
901 * @param key The integer keycode for the event.
902 */
903 public void sendKeyDownUpSync(int key) {
904 sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, key));
905 sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, key));
906 }
907
908 /**
909 * Higher-level method for sending both the down and up key events for a
910 * particular character key code. Equivalent to creating both KeyEvent
911 * objects by hand and calling {@link #sendKeySync}. The event appears
912 * as if it came from keyboard 0, the built in one.
913 *
914 * @param keyCode The key code of the character to send.
915 */
916 public void sendCharacterSync(int keyCode) {
917 sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
918 sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
919 }
920
921 /**
922 * Dispatch a pointer event. Finished at some point after the recipient has
923 * returned from its event processing, though it may <em>not</em> have
924 * completely finished reacting from the event -- for example, if it needs
925 * to update its display as a result, it may still be in the process of
926 * doing that.
927 *
928 * @param event A motion event describing the pointer action. (As noted in
929 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
930 * {@link SystemClock#uptimeMillis()} as the timebase.
931 */
932 public void sendPointerSync(MotionEvent event) {
933 validateNotAppThread();
Jeff Brownac143512012-04-05 18:57:33 -0700934 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
935 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700937 InputManager.getInstance().injectInputEvent(event,
938 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 }
940
941 /**
942 * Dispatch a trackball event. Finished at some point after the recipient has
943 * returned from its event processing, though it may <em>not</em> have
944 * completely finished reacting from the event -- for example, if it needs
945 * to update its display as a result, it may still be in the process of
946 * doing that.
947 *
948 * @param event A motion event describing the trackball action. (As noted in
949 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
950 * {@link SystemClock#uptimeMillis()} as the timebase.
951 */
952 public void sendTrackballEventSync(MotionEvent event) {
953 validateNotAppThread();
Jeff Brownac143512012-04-05 18:57:33 -0700954 if ((event.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
955 event.setSource(InputDevice.SOURCE_TRACKBALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 }
Jeff Brown9f25b7f2012-04-10 14:30:49 -0700957 InputManager.getInstance().injectInputEvent(event,
958 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
960
961 /**
962 * Perform instantiation of the process's {@link Application} object. The
963 * default implementation provides the normal system behavior.
964 *
965 * @param cl The ClassLoader with which to instantiate the object.
966 * @param className The name of the class implementing the Application
967 * object.
968 * @param context The context to initialize the application with
969 *
970 * @return The newly instantiated Application object.
971 */
972 public Application newApplication(ClassLoader cl, String className, Context context)
973 throws InstantiationException, IllegalAccessException,
974 ClassNotFoundException {
975 return newApplication(cl.loadClass(className), context);
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 clazz The class used to create an Application object from.
983 * @param context The context to initialize the application with
984 *
985 * @return The newly instantiated Application object.
986 */
987 static public Application newApplication(Class<?> clazz, Context context)
988 throws InstantiationException, IllegalAccessException,
989 ClassNotFoundException {
990 Application app = (Application)clazz.newInstance();
991 app.attach(context);
992 return app;
993 }
994
995 /**
996 * Perform calling of the application's {@link Application#onCreate}
997 * method. The default implementation simply calls through to that method.
Dianne Hackborn6ae8d182012-05-23 13:12:42 -0700998 *
999 * <p>Note: This method will be called immediately after {@link #onCreate(Bundle)}.
1000 * Often instrumentation tests start their test thread in onCreate(); you
1001 * need to be careful of races between these. (Well between it and
1002 * everything else, but let's start here.)
1003 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 * @param app The application being created.
1005 */
1006 public void callApplicationOnCreate(Application app) {
1007 app.onCreate();
1008 }
1009
1010 /**
1011 * Perform instantiation of an {@link Activity} object. This method is intended for use with
1012 * unit tests, such as android.test.ActivityUnitTestCase. The activity will be useable
1013 * locally but will be missing some of the linkages necessary for use within the sytem.
1014 *
1015 * @param clazz The Class of the desired Activity
1016 * @param context The base context for the activity to use
1017 * @param token The token for this activity to communicate with
1018 * @param application The application object (if any)
1019 * @param intent The intent that started this Activity
1020 * @param info ActivityInfo from the manifest
1021 * @param title The title, typically retrieved from the ActivityInfo record
1022 * @param parent The parent Activity (if any)
1023 * @param id The embedded Id (if any)
1024 * @param lastNonConfigurationInstance Arbitrary object that will be
1025 * available via {@link Activity#getLastNonConfigurationInstance()
1026 * Activity.getLastNonConfigurationInstance()}.
1027 * @return Returns the instantiated activity
1028 * @throws InstantiationException
1029 * @throws IllegalAccessException
1030 */
1031 public Activity newActivity(Class<?> clazz, Context context,
1032 IBinder token, Application application, Intent intent, ActivityInfo info,
1033 CharSequence title, Activity parent, String id,
1034 Object lastNonConfigurationInstance) throws InstantiationException,
1035 IllegalAccessException {
1036 Activity activity = (Activity)clazz.newInstance();
1037 ActivityThread aThread = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001038 activity.attach(context, aThread, this, token, application, intent,
1039 info, title, parent, id,
1040 (Activity.NonConfigurationInstances)lastNonConfigurationInstance,
1041 new Configuration());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 return activity;
1043 }
1044
1045 /**
1046 * Perform instantiation of the process's {@link Activity} object. The
1047 * default implementation provides the normal system behavior.
1048 *
1049 * @param cl The ClassLoader with which to instantiate the object.
1050 * @param className The name of the class implementing the Activity
1051 * object.
1052 * @param intent The Intent object that specified the activity class being
1053 * instantiated.
1054 *
1055 * @return The newly instantiated Activity object.
1056 */
1057 public Activity newActivity(ClassLoader cl, String className,
1058 Intent intent)
1059 throws InstantiationException, IllegalAccessException,
1060 ClassNotFoundException {
1061 return (Activity)cl.loadClass(className).newInstance();
1062 }
1063
1064 /**
1065 * Perform calling of an activity's {@link Activity#onCreate}
1066 * method. The default implementation simply calls through to that method.
1067 *
1068 * @param activity The activity being created.
1069 * @param icicle The previously frozen state (or null) to pass through to
1070 * onCreate().
1071 */
1072 public void callActivityOnCreate(Activity activity, Bundle icicle) {
1073 if (mWaitingActivities != null) {
1074 synchronized (mSync) {
1075 final int N = mWaitingActivities.size();
1076 for (int i=0; i<N; i++) {
1077 final ActivityWaiter aw = mWaitingActivities.get(i);
1078 final Intent intent = aw.intent;
1079 if (intent.filterEquals(activity.getIntent())) {
1080 aw.activity = activity;
1081 mMessageQueue.addIdleHandler(new ActivityGoing(aw));
1082 }
1083 }
1084 }
1085 }
1086
Dianne Hackborn5be8de32011-05-24 18:11:57 -07001087 activity.performCreate(icicle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088
1089 if (mActivityMonitors != null) {
1090 synchronized (mSync) {
1091 final int N = mActivityMonitors.size();
1092 for (int i=0; i<N; i++) {
1093 final ActivityMonitor am = mActivityMonitors.get(i);
1094 am.match(activity, activity, activity.getIntent());
1095 }
1096 }
1097 }
1098 }
1099
1100 public void callActivityOnDestroy(Activity activity) {
Brett Chabot18f9ce02010-05-12 12:41:50 -07001101 // TODO: the following block causes intermittent hangs when using startActivity
1102 // temporarily comment out until root cause is fixed (bug 2630683)
1103// if (mWaitingActivities != null) {
1104// synchronized (mSync) {
1105// final int N = mWaitingActivities.size();
1106// for (int i=0; i<N; i++) {
1107// final ActivityWaiter aw = mWaitingActivities.get(i);
1108// final Intent intent = aw.intent;
1109// if (intent.filterEquals(activity.getIntent())) {
1110// aw.activity = activity;
1111// mMessageQueue.addIdleHandler(new ActivityGoing(aw));
1112// }
1113// }
1114// }
1115// }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001117 activity.performDestroy();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118
1119 if (mActivityMonitors != null) {
1120 synchronized (mSync) {
1121 final int N = mActivityMonitors.size();
1122 for (int i=0; i<N; i++) {
1123 final ActivityMonitor am = mActivityMonitors.get(i);
1124 am.match(activity, activity, activity.getIntent());
1125 }
1126 }
1127 }
1128 }
1129
1130 /**
1131 * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
1132 * method. The default implementation simply calls through to that method.
1133 *
1134 * @param activity The activity being restored.
1135 * @param savedInstanceState The previously saved state being restored.
1136 */
1137 public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState) {
1138 activity.performRestoreInstanceState(savedInstanceState);
1139 }
1140
1141 /**
1142 * Perform calling of an activity's {@link Activity#onPostCreate} method.
1143 * The default implementation simply calls through to that method.
1144 *
1145 * @param activity The activity being created.
1146 * @param icicle The previously frozen state (or null) to pass through to
1147 * onPostCreate().
1148 */
1149 public void callActivityOnPostCreate(Activity activity, Bundle icicle) {
1150 activity.onPostCreate(icicle);
1151 }
1152
1153 /**
1154 * Perform calling of an activity's {@link Activity#onNewIntent}
1155 * method. The default implementation simply calls through to that method.
1156 *
1157 * @param activity The activity receiving a new Intent.
1158 * @param intent The new intent being received.
1159 */
1160 public void callActivityOnNewIntent(Activity activity, Intent intent) {
1161 activity.onNewIntent(intent);
1162 }
1163
1164 /**
1165 * Perform calling of an activity's {@link Activity#onStart}
1166 * method. The default implementation simply calls through to that method.
1167 *
1168 * @param activity The activity being started.
1169 */
1170 public void callActivityOnStart(Activity activity) {
1171 activity.onStart();
1172 }
1173
1174 /**
1175 * Perform calling of an activity's {@link Activity#onRestart}
1176 * method. The default implementation simply calls through to that method.
1177 *
1178 * @param activity The activity being restarted.
1179 */
1180 public void callActivityOnRestart(Activity activity) {
1181 activity.onRestart();
1182 }
1183
1184 /**
1185 * Perform calling of an activity's {@link Activity#onResume} method. The
1186 * default implementation simply calls through to that method.
1187 *
1188 * @param activity The activity being resumed.
1189 */
1190 public void callActivityOnResume(Activity activity) {
Jeff Hamilton52d32032011-01-08 15:31:26 -06001191 activity.mResumed = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 activity.onResume();
1193
1194 if (mActivityMonitors != null) {
1195 synchronized (mSync) {
1196 final int N = mActivityMonitors.size();
1197 for (int i=0; i<N; i++) {
1198 final ActivityMonitor am = mActivityMonitors.get(i);
1199 am.match(activity, activity, activity.getIntent());
1200 }
1201 }
1202 }
1203 }
1204
1205 /**
1206 * Perform calling of an activity's {@link Activity#onStop}
1207 * method. The default implementation simply calls through to that method.
1208 *
1209 * @param activity The activity being stopped.
1210 */
1211 public void callActivityOnStop(Activity activity) {
1212 activity.onStop();
1213 }
1214
1215 /**
Newton Allenc5027442013-08-13 11:22:32 -07001216 * Perform calling of an activity's {@link Activity#onSaveInstanceState}
1217 * method. The default implementation simply calls through to that method.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 *
1219 * @param activity The activity being saved.
1220 * @param outState The bundle to pass to the call.
1221 */
1222 public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
1223 activity.performSaveInstanceState(outState);
1224 }
1225
1226 /**
1227 * Perform calling of an activity's {@link Activity#onPause} method. The
1228 * default implementation simply calls through to that method.
1229 *
1230 * @param activity The activity being paused.
1231 */
1232 public void callActivityOnPause(Activity activity) {
1233 activity.performPause();
1234 }
1235
1236 /**
1237 * Perform calling of an activity's {@link Activity#onUserLeaveHint} method.
1238 * The default implementation simply calls through to that method.
1239 *
1240 * @param activity The activity being notified that the user has navigated away
1241 */
1242 public void callActivityOnUserLeaving(Activity activity) {
1243 activity.performUserLeaving();
1244 }
1245
1246 /*
1247 * Starts allocation counting. This triggers a gc and resets the counts.
1248 */
1249 public void startAllocCounting() {
1250 // Before we start trigger a GC and reset the debug counts. Run the
1251 // finalizers and another GC before starting and stopping the alloc
1252 // counts. This will free up any objects that were just sitting around
1253 // waiting for their finalizers to be run.
1254 Runtime.getRuntime().gc();
1255 Runtime.getRuntime().runFinalization();
1256 Runtime.getRuntime().gc();
1257
1258 Debug.resetAllCounts();
1259
1260 // start the counts
1261 Debug.startAllocCounting();
1262 }
1263
1264 /*
1265 * Stops allocation counting.
1266 */
1267 public void stopAllocCounting() {
1268 Runtime.getRuntime().gc();
1269 Runtime.getRuntime().runFinalization();
1270 Runtime.getRuntime().gc();
1271 Debug.stopAllocCounting();
1272 }
1273
1274 /**
1275 * If Results already contains Key, it appends Value to the key's ArrayList
1276 * associated with the key. If the key doesn't already exist in results, it
1277 * adds the key/value pair to results.
1278 */
1279 private void addValue(String key, int value, Bundle results) {
1280 if (results.containsKey(key)) {
1281 List<Integer> list = results.getIntegerArrayList(key);
1282 if (list != null) {
1283 list.add(value);
1284 }
1285 } else {
1286 ArrayList<Integer> list = new ArrayList<Integer>();
1287 list.add(value);
1288 results.putIntegerArrayList(key, list);
1289 }
1290 }
1291
1292 /**
1293 * Returns a bundle with the current results from the allocation counting.
1294 */
1295 public Bundle getAllocCounts() {
1296 Bundle results = new Bundle();
1297 results.putLong("global_alloc_count", Debug.getGlobalAllocCount());
1298 results.putLong("global_alloc_size", Debug.getGlobalAllocSize());
1299 results.putLong("global_freed_count", Debug.getGlobalFreedCount());
1300 results.putLong("global_freed_size", Debug.getGlobalFreedSize());
1301 results.putLong("gc_invocation_count", Debug.getGlobalGcInvocationCount());
1302 return results;
1303 }
1304
1305 /**
1306 * Returns a bundle with the counts for various binder counts for this process. Currently the only two that are
1307 * reported are the number of send and the number of received transactions.
1308 */
1309 public Bundle getBinderCounts() {
1310 Bundle results = new Bundle();
1311 results.putLong("sent_transactions", Debug.getBinderSentTransactions());
1312 results.putLong("received_transactions", Debug.getBinderReceivedTransactions());
1313 return results;
1314 }
1315
1316 /**
1317 * Description of a Activity execution result to return to the original
1318 * activity.
1319 */
1320 public static final class ActivityResult {
1321 /**
1322 * Create a new activity result. See {@link Activity#setResult} for
1323 * more information.
1324 *
1325 * @param resultCode The result code to propagate back to the
1326 * originating activity, often RESULT_CANCELED or RESULT_OK
1327 * @param resultData The data to propagate back to the originating
1328 * activity.
1329 */
1330 public ActivityResult(int resultCode, Intent resultData) {
1331 mResultCode = resultCode;
1332 mResultData = resultData;
1333 }
1334
1335 /**
1336 * Retrieve the result code contained in this result.
1337 */
1338 public int getResultCode() {
1339 return mResultCode;
1340 }
1341
1342 /**
1343 * Retrieve the data contained in this result.
1344 */
1345 public Intent getResultData() {
1346 return mResultData;
1347 }
1348
1349 private final int mResultCode;
1350 private final Intent mResultData;
1351 }
1352
1353 /**
1354 * Execute a startActivity call made by the application. The default
1355 * implementation takes care of updating any active {@link ActivityMonitor}
1356 * objects and dispatches this call to the system activity manager; you can
1357 * override this to watch for the application to start an activity, and
1358 * modify what happens when it does.
1359 *
1360 * <p>This method returns an {@link ActivityResult} object, which you can
1361 * use when intercepting application calls to avoid performing the start
1362 * activity action but still return the result the application is
1363 * expecting. To do this, override this method to catch the call to start
1364 * activity so that it returns a new ActivityResult containing the results
1365 * you would like the application to see, and don't call up to the super
1366 * class. Note that an application is only expecting a result if
1367 * <var>requestCode</var> is &gt;= 0.
1368 *
1369 * <p>This method throws {@link android.content.ActivityNotFoundException}
1370 * if there was no Activity found to run the given Intent.
1371 *
1372 * @param who The Context from which the activity is being started.
1373 * @param contextThread The main thread of the Context from which the activity
1374 * is being started.
1375 * @param token Internal token identifying to the system who is starting
1376 * the activity; may be null.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001377 * @param target Which activity is performing the start (and thus receiving
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 * any result); may be null if this call is not being made
1379 * from an activity.
1380 * @param intent The actual Intent to start.
1381 * @param requestCode Identifier for this request's result; less than zero
1382 * if the caller is not expecting a result.
Dianne Hackborna4972e92012-03-14 10:38:05 -07001383 * @param options Addition options.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 *
1385 * @return To force the return of a particular result, return an
1386 * ActivityResult object containing the desired data; otherwise
1387 * return null. The default implementation always returns null.
1388 *
1389 * @throws android.content.ActivityNotFoundException
1390 *
1391 * @see Activity#startActivity(Intent)
1392 * @see Activity#startActivityForResult(Intent, int)
1393 * @see Activity#startActivityFromChild
1394 *
1395 * {@hide}
1396 */
1397 public ActivityResult execStartActivity(
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001398 Context who, IBinder contextThread, IBinder token, Activity target,
Dianne Hackborna4972e92012-03-14 10:38:05 -07001399 Intent intent, int requestCode, Bundle options) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 IApplicationThread whoThread = (IApplicationThread) contextThread;
1401 if (mActivityMonitors != null) {
1402 synchronized (mSync) {
1403 final int N = mActivityMonitors.size();
1404 for (int i=0; i<N; i++) {
1405 final ActivityMonitor am = mActivityMonitors.get(i);
1406 if (am.match(who, null, intent)) {
1407 am.mHits++;
1408 if (am.isBlocking()) {
1409 return requestCode >= 0 ? am.getResult() : null;
1410 }
1411 break;
1412 }
1413 }
1414 }
1415 }
1416 try {
Jeff Sharkey678d04f2012-03-23 15:41:58 -07001417 intent.migrateExtraStreamToClipData();
Jeff Sharkeya14acd22013-04-02 18:27:45 -07001418 intent.prepareToLeaveProcess();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 int result = ActivityManagerNative.getDefault()
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001420 .startActivity(whoThread, who.getBasePackageName(), intent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 intent.resolveTypeIfNeeded(who.getContentResolver()),
Dianne Hackborna4972e92012-03-14 10:38:05 -07001422 token, target != null ? target.mEmbeddedID : null,
1423 requestCode, 0, null, null, options);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001424 checkStartActivityResult(result, intent);
1425 } catch (RemoteException e) {
1426 }
1427 return null;
1428 }
1429
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001430 /**
Dianne Hackborn91097de2014-04-04 18:02:06 -07001431 * Like {@link #execStartActivity},
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001432 * but accepts an array of activities to be started. Note that active
1433 * {@link ActivityMonitor} objects only match against the first activity in
1434 * the array.
1435 *
1436 * {@hide}
1437 */
1438 public void execStartActivities(Context who, IBinder contextThread,
Dianne Hackborna4972e92012-03-14 10:38:05 -07001439 IBinder token, Activity target, Intent[] intents, Bundle options) {
Amith Yamasaniea7e9152012-09-24 16:11:18 -07001440 execStartActivitiesAsUser(who, contextThread, token, target, intents, options,
1441 UserHandle.myUserId());
1442 }
1443
1444 /**
Dianne Hackborn91097de2014-04-04 18:02:06 -07001445 * Like {@link #execStartActivity},
Amith Yamasaniea7e9152012-09-24 16:11:18 -07001446 * but accepts an array of activities to be started. Note that active
1447 * {@link ActivityMonitor} objects only match against the first activity in
1448 * the array.
1449 *
1450 * {@hide}
1451 */
1452 public void execStartActivitiesAsUser(Context who, IBinder contextThread,
1453 IBinder token, Activity target, Intent[] intents, Bundle options,
1454 int userId) {
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001455 IApplicationThread whoThread = (IApplicationThread) contextThread;
1456 if (mActivityMonitors != null) {
1457 synchronized (mSync) {
1458 final int N = mActivityMonitors.size();
1459 for (int i=0; i<N; i++) {
1460 final ActivityMonitor am = mActivityMonitors.get(i);
1461 if (am.match(who, null, intents[0])) {
1462 am.mHits++;
1463 if (am.isBlocking()) {
1464 return;
1465 }
1466 break;
1467 }
1468 }
1469 }
1470 }
1471 try {
1472 String[] resolvedTypes = new String[intents.length];
1473 for (int i=0; i<intents.length; i++) {
Jeff Sharkeya14acd22013-04-02 18:27:45 -07001474 intents[i].migrateExtraStreamToClipData();
1475 intents[i].prepareToLeaveProcess();
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001476 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
1477 }
1478 int result = ActivityManagerNative.getDefault()
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001479 .startActivities(whoThread, who.getBasePackageName(), intents, resolvedTypes,
1480 token, options, userId);
Dianne Hackborn621e17d2010-11-22 15:59:56 -08001481 checkStartActivityResult(result, intents[0]);
1482 } catch (RemoteException e) {
1483 }
1484 }
1485
1486 /**
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001487 * Like {@link #execStartActivity(android.content.Context, android.os.IBinder,
1488 * android.os.IBinder, Fragment, android.content.Intent, int, android.os.Bundle)},
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001489 * but for calls from a {#link Fragment}.
1490 *
1491 * @param who The Context from which the activity is being started.
1492 * @param contextThread The main thread of the Context from which the activity
1493 * is being started.
1494 * @param token Internal token identifying to the system who is starting
1495 * the activity; may be null.
1496 * @param target Which fragment is performing the start (and thus receiving
1497 * any result).
1498 * @param intent The actual Intent to start.
1499 * @param requestCode Identifier for this request's result; less than zero
1500 * if the caller is not expecting a result.
1501 *
1502 * @return To force the return of a particular result, return an
1503 * ActivityResult object containing the desired data; otherwise
1504 * return null. The default implementation always returns null.
1505 *
1506 * @throws android.content.ActivityNotFoundException
1507 *
1508 * @see Activity#startActivity(Intent)
1509 * @see Activity#startActivityForResult(Intent, int)
1510 * @see Activity#startActivityFromChild
1511 *
1512 * {@hide}
1513 */
1514 public ActivityResult execStartActivity(
1515 Context who, IBinder contextThread, IBinder token, Fragment target,
Dianne Hackborna4972e92012-03-14 10:38:05 -07001516 Intent intent, int requestCode, Bundle options) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001517 IApplicationThread whoThread = (IApplicationThread) contextThread;
1518 if (mActivityMonitors != null) {
1519 synchronized (mSync) {
1520 final int N = mActivityMonitors.size();
1521 for (int i=0; i<N; i++) {
1522 final ActivityMonitor am = mActivityMonitors.get(i);
1523 if (am.match(who, null, intent)) {
1524 am.mHits++;
1525 if (am.isBlocking()) {
1526 return requestCode >= 0 ? am.getResult() : null;
1527 }
1528 break;
1529 }
1530 }
1531 }
1532 }
1533 try {
Jeff Sharkey678d04f2012-03-23 15:41:58 -07001534 intent.migrateExtraStreamToClipData();
Jeff Sharkeya14acd22013-04-02 18:27:45 -07001535 intent.prepareToLeaveProcess();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001536 int result = ActivityManagerNative.getDefault()
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001537 .startActivity(whoThread, who.getBasePackageName(), intent,
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001538 intent.resolveTypeIfNeeded(who.getContentResolver()),
Dianne Hackborna4972e92012-03-14 10:38:05 -07001539 token, target != null ? target.mWho : null,
1540 requestCode, 0, null, null, options);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001541 checkStartActivityResult(result, intent);
1542 } catch (RemoteException e) {
1543 }
1544 return null;
1545 }
1546
Dianne Hackbornf1c26e22012-08-23 13:54:58 -07001547 /**
Dianne Hackborn91097de2014-04-04 18:02:06 -07001548 * Like {@link #execStartActivity}, but for starting as a particular user.
Dianne Hackbornf1c26e22012-08-23 13:54:58 -07001549 *
1550 * @param who The Context from which the activity is being started.
1551 * @param contextThread The main thread of the Context from which the activity
1552 * is being started.
1553 * @param token Internal token identifying to the system who is starting
1554 * the activity; may be null.
1555 * @param target Which fragment is performing the start (and thus receiving
1556 * any result).
1557 * @param intent The actual Intent to start.
1558 * @param requestCode Identifier for this request's result; less than zero
1559 * if the caller is not expecting a result.
1560 *
1561 * @return To force the return of a particular result, return an
1562 * ActivityResult object containing the desired data; otherwise
1563 * return null. The default implementation always returns null.
1564 *
1565 * @throws android.content.ActivityNotFoundException
1566 *
1567 * @see Activity#startActivity(Intent)
1568 * @see Activity#startActivityForResult(Intent, int)
1569 * @see Activity#startActivityFromChild
1570 *
1571 * {@hide}
1572 */
1573 public ActivityResult execStartActivity(
1574 Context who, IBinder contextThread, IBinder token, Activity target,
1575 Intent intent, int requestCode, Bundle options, UserHandle user) {
1576 IApplicationThread whoThread = (IApplicationThread) contextThread;
1577 if (mActivityMonitors != null) {
1578 synchronized (mSync) {
1579 final int N = mActivityMonitors.size();
1580 for (int i=0; i<N; i++) {
1581 final ActivityMonitor am = mActivityMonitors.get(i);
1582 if (am.match(who, null, intent)) {
1583 am.mHits++;
1584 if (am.isBlocking()) {
1585 return requestCode >= 0 ? am.getResult() : null;
1586 }
1587 break;
1588 }
1589 }
1590 }
1591 }
1592 try {
Dianne Hackbornf1c26e22012-08-23 13:54:58 -07001593 intent.migrateExtraStreamToClipData();
Jeff Sharkeya14acd22013-04-02 18:27:45 -07001594 intent.prepareToLeaveProcess();
Dianne Hackbornf1c26e22012-08-23 13:54:58 -07001595 int result = ActivityManagerNative.getDefault()
Dianne Hackbornf265ea92013-01-31 15:00:51 -08001596 .startActivityAsUser(whoThread, who.getBasePackageName(), intent,
Dianne Hackbornf1c26e22012-08-23 13:54:58 -07001597 intent.resolveTypeIfNeeded(who.getContentResolver()),
1598 token, target != null ? target.mEmbeddedID : null,
1599 requestCode, 0, null, null, options, user.getIdentifier());
1600 checkStartActivityResult(result, intent);
1601 } catch (RemoteException e) {
1602 }
1603 return null;
1604 }
1605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 /*package*/ final void init(ActivityThread thread,
1607 Context instrContext, Context appContext, ComponentName component,
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001608 IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 mThread = thread;
1610 mMessageQueue = mThread.getLooper().myQueue();
1611 mInstrContext = instrContext;
1612 mAppContext = appContext;
1613 mComponent = component;
1614 mWatcher = watcher;
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001615 mUiAutomationConnection = uiAutomationConnection;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 }
1617
Dianne Hackborn91097de2014-04-04 18:02:06 -07001618 /** @hide */
1619 public static void checkStartActivityResult(int res, Object intent) {
Dianne Hackborna4972e92012-03-14 10:38:05 -07001620 if (res >= ActivityManager.START_SUCCESS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 return;
1622 }
1623
1624 switch (res) {
Dianne Hackborna4972e92012-03-14 10:38:05 -07001625 case ActivityManager.START_INTENT_NOT_RESOLVED:
1626 case ActivityManager.START_CLASS_NOT_FOUND:
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07001627 if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628 throw new ActivityNotFoundException(
1629 "Unable to find explicit activity class "
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07001630 + ((Intent)intent).getComponent().toShortString()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631 + "; have you declared this activity in your AndroidManifest.xml?");
1632 throw new ActivityNotFoundException(
1633 "No Activity found to handle " + intent);
Dianne Hackborna4972e92012-03-14 10:38:05 -07001634 case ActivityManager.START_PERMISSION_DENIED:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 throw new SecurityException("Not allowed to start activity "
1636 + intent);
Dianne Hackborna4972e92012-03-14 10:38:05 -07001637 case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 throw new AndroidRuntimeException(
1639 "FORWARD_RESULT_FLAG used while also requesting a result");
Dianne Hackborna4972e92012-03-14 10:38:05 -07001640 case ActivityManager.START_NOT_ACTIVITY:
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07001641 throw new IllegalArgumentException(
1642 "PendingIntent is not an activity");
Dianne Hackborn91097de2014-04-04 18:02:06 -07001643 case ActivityManager.START_NOT_VOICE_COMPATIBLE:
1644 throw new SecurityException(
1645 "Starting under voice control not allowed for: " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 default:
1647 throw new AndroidRuntimeException("Unknown error code "
1648 + res + " when starting " + intent);
1649 }
1650 }
1651
1652 private final void validateNotAppThread() {
Kristian Monsen0a303282013-01-18 14:50:07 -08001653 if (Looper.myLooper() == Looper.getMainLooper()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 throw new RuntimeException(
1655 "This method can not be called from the main application thread");
1656 }
1657 }
1658
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001659 /**
1660 * Gets the {@link UiAutomation} instance.
1661 * <p>
1662 * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation}
1663 * work across application boundaries while the APIs exposed by the instrumentation
1664 * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will
1665 * not allow you to inject the event in an app different from the instrumentation
1666 * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)}
1667 * will work regardless of the current application.
1668 * </p>
1669 * <p>
1670 * A typical test case should be using either the {@link UiAutomation} or
1671 * {@link Instrumentation} APIs. Using both APIs at the same time is not
1672 * a mistake by itself but a client has to be aware of the APIs limitations.
1673 * </p>
1674 * @return The UI automation instance.
1675 *
1676 * @see UiAutomation
1677 */
1678 public UiAutomation getUiAutomation() {
1679 if (mUiAutomationConnection != null) {
1680 if (mUiAutomation == null) {
1681 mUiAutomation = new UiAutomation(getTargetContext().getMainLooper(),
1682 mUiAutomationConnection);
1683 mUiAutomation.connect();
1684 }
1685 return mUiAutomation;
1686 }
1687 return null;
1688 }
1689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 private final class InstrumentationThread extends Thread {
1691 public InstrumentationThread(String name) {
1692 super(name);
1693 }
1694 public void run() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 try {
1696 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
1697 } catch (RuntimeException e) {
1698 Log.w(TAG, "Exception setting priority of instrumentation thread "
1699 + Process.myTid(), e);
1700 }
1701 if (mAutomaticPerformanceSnapshots) {
1702 startPerformanceSnapshot();
1703 }
1704 onStart();
1705 }
1706 }
Svetoslav Ganov80943d82013-01-02 10:25:37 -08001707
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 private static final class EmptyRunnable implements Runnable {
1709 public void run() {
1710 }
1711 }
1712
1713 private static final class SyncRunnable implements Runnable {
1714 private final Runnable mTarget;
1715 private boolean mComplete;
1716
1717 public SyncRunnable(Runnable target) {
1718 mTarget = target;
1719 }
1720
1721 public void run() {
1722 mTarget.run();
1723 synchronized (this) {
1724 mComplete = true;
1725 notifyAll();
1726 }
1727 }
1728
1729 public void waitForComplete() {
1730 synchronized (this) {
1731 while (!mComplete) {
1732 try {
1733 wait();
1734 } catch (InterruptedException e) {
1735 }
1736 }
1737 }
1738 }
1739 }
1740
1741 private static final class ActivityWaiter {
1742 public final Intent intent;
1743 public Activity activity;
1744
1745 public ActivityWaiter(Intent _intent) {
1746 intent = _intent;
1747 }
1748 }
1749
1750 private final class ActivityGoing implements MessageQueue.IdleHandler {
1751 private final ActivityWaiter mWaiter;
1752
1753 public ActivityGoing(ActivityWaiter waiter) {
1754 mWaiter = waiter;
1755 }
1756
1757 public final boolean queueIdle() {
1758 synchronized (mSync) {
1759 mWaitingActivities.remove(mWaiter);
1760 mSync.notifyAll();
1761 }
1762 return false;
1763 }
1764 }
1765
1766 private static final class Idler implements MessageQueue.IdleHandler {
1767 private final Runnable mCallback;
1768 private boolean mIdle;
1769
1770 public Idler(Runnable callback) {
1771 mCallback = callback;
1772 mIdle = false;
1773 }
1774
1775 public final boolean queueIdle() {
1776 if (mCallback != null) {
1777 mCallback.run();
1778 }
1779 synchronized (this) {
1780 mIdle = true;
1781 notifyAll();
1782 }
1783 return false;
1784 }
1785
1786 public void waitForIdle() {
1787 synchronized (this) {
1788 while (!mIdle) {
1789 try {
1790 wait();
1791 } catch (InterruptedException e) {
1792 }
1793 }
1794 }
1795 }
1796 }
1797}