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