1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.app; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.content.ActivityNotFoundException; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.pm.ActivityInfo; 30 import android.content.pm.PackageManager; 31 import android.content.res.Configuration; 32 import android.hardware.input.InputManager; 33 import android.hardware.input.InputManagerGlobal; 34 import android.net.Uri; 35 import android.os.Build; 36 import android.os.Bundle; 37 import android.os.Debug; 38 import android.os.IBinder; 39 import android.os.Looper; 40 import android.os.MessageQueue; 41 import android.os.PerformanceCollector; 42 import android.os.PersistableBundle; 43 import android.os.Process; 44 import android.os.RemoteException; 45 import android.os.ServiceManager; 46 import android.os.SystemClock; 47 import android.os.SystemProperties; 48 import android.os.TestLooperManager; 49 import android.os.UserHandle; 50 import android.os.UserManager; 51 import android.util.AndroidRuntimeException; 52 import android.util.Log; 53 import android.view.Display; 54 import android.view.IWindowManager; 55 import android.view.InputDevice; 56 import android.view.KeyCharacterMap; 57 import android.view.KeyEvent; 58 import android.view.MotionEvent; 59 import android.view.SurfaceControl; 60 import android.view.ViewConfiguration; 61 import android.view.Window; 62 import android.view.WindowManagerGlobal; 63 64 import com.android.internal.content.ReferrerIntent; 65 66 import java.io.File; 67 import java.lang.annotation.Retention; 68 import java.lang.annotation.RetentionPolicy; 69 import java.util.ArrayList; 70 import java.util.List; 71 import java.util.Objects; 72 import java.util.StringJoiner; 73 import java.util.concurrent.TimeoutException; 74 75 /** 76 * Base class for implementing application instrumentation code. When running 77 * with instrumentation turned on, this class will be instantiated for you 78 * before any of the application code, allowing you to monitor all of the 79 * interaction the system has with the application. An Instrumentation 80 * implementation is described to the system through an AndroidManifest.xml's 81 * <instrumentation> tag. 82 */ 83 @android.ravenwood.annotation.RavenwoodKeepPartialClass 84 public class Instrumentation { 85 86 /** 87 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 88 * identifies the class that is writing the report. This can be used to provide more structured 89 * logging or reporting capabilities in the IInstrumentationWatcher. 90 */ 91 public static final String REPORT_KEY_IDENTIFIER = "id"; 92 /** 93 * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 94 * identifies a string which can simply be printed to the output stream. Using these streams 95 * provides a "pretty printer" version of the status & final packets. Any bundles including 96 * this key should also include the complete set of raw key/value pairs, so that the 97 * instrumentation can also be launched, and results collected, by an automated system. 98 */ 99 public static final String REPORT_KEY_STREAMRESULT = "stream"; 100 101 private static final String TAG = "Instrumentation"; 102 103 private static final long CONNECT_TIMEOUT_MILLIS = 60_000; 104 105 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 106 107 // If set, will print the stack trace for activity starts within the process 108 static final boolean DEBUG_START_ACTIVITY = Build.IS_DEBUGGABLE && 109 SystemProperties.getBoolean("persist.wm.debug.start_activity", false); 110 111 /** 112 * @hide 113 */ 114 @Retention(RetentionPolicy.SOURCE) 115 @IntDef({0, UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES, 116 UiAutomation.FLAG_DONT_USE_ACCESSIBILITY}) 117 public @interface UiAutomationFlags {}; 118 119 120 private final Object mSync = new Object(); 121 private ActivityThread mThread = null; 122 private MessageQueue mMessageQueue = null; 123 private Context mInstrContext; 124 private Context mAppContext; 125 private ComponentName mComponent; 126 private Thread mRunner; 127 private List<ActivityWaiter> mWaitingActivities; 128 private List<ActivityMonitor> mActivityMonitors; 129 private IInstrumentationWatcher mWatcher; 130 private IUiAutomationConnection mUiAutomationConnection; 131 private boolean mAutomaticPerformanceSnapshots = false; 132 private PerformanceCollector mPerformanceCollector; 133 private Bundle mPerfMetrics = new Bundle(); 134 private UiAutomation mUiAutomation; 135 private final Object mAnimationCompleteLock = new Object(); 136 137 @android.ravenwood.annotation.RavenwoodKeep Instrumentation()138 public Instrumentation() { 139 } 140 141 /** 142 * Called for methods that shouldn't be called by standard apps and 143 * should only be used in instrumentation environments. This is not 144 * security feature as these classes will still be accessible through 145 * reflection, but it will serve as noticeable discouragement from 146 * doing such a thing. 147 */ 148 @android.ravenwood.annotation.RavenwoodKeep checkInstrumenting(String method)149 private void checkInstrumenting(String method) { 150 // Check if we have an instrumentation context, as init should only get called by 151 // the system in startup processes that are being instrumented. 152 if (mInstrContext == null) { 153 throw new RuntimeException(method + 154 " cannot be called outside of instrumented processes"); 155 } 156 } 157 158 /** 159 * Returns if it is being called in an instrumentation environment. 160 * 161 * @hide 162 */ 163 @android.ravenwood.annotation.RavenwoodKeep isInstrumenting()164 public boolean isInstrumenting() { 165 // Check if we have an instrumentation context, as init should only get called by 166 // the system in startup processes that are being instrumented. 167 if (mInstrContext == null) { 168 return false; 169 } 170 return true; 171 } 172 173 /** 174 * Called when the instrumentation is starting, before any application code 175 * has been loaded. Usually this will be implemented to simply call 176 * {@link #start} to begin the instrumentation thread, which will then 177 * continue execution in {@link #onStart}. 178 * 179 * <p>If you do not need your own thread -- that is you are writing your 180 * instrumentation to be completely asynchronous (returning to the event 181 * loop so that the application can run), you can simply begin your 182 * instrumentation here, for example call {@link Context#startActivity} to 183 * begin the appropriate first activity of the application. 184 * 185 * @param arguments Any additional arguments that were supplied when the 186 * instrumentation was started. 187 */ onCreate(Bundle arguments)188 public void onCreate(Bundle arguments) { 189 } 190 191 /** 192 * Create and start a new thread in which to run instrumentation. This new 193 * thread will call to {@link #onStart} where you can implement the 194 * instrumentation. 195 */ start()196 public void start() { 197 if (mRunner != null) { 198 throw new RuntimeException("Instrumentation already started"); 199 } 200 mRunner = new InstrumentationThread("Instr: " + getClass().getName()); 201 mRunner.start(); 202 } 203 204 /** 205 * Method where the instrumentation thread enters execution. This allows 206 * you to run your instrumentation code in a separate thread than the 207 * application, so that it can perform blocking operation such as 208 * {@link #sendKeySync} or {@link #startActivitySync}. 209 * 210 * <p>You will typically want to call finish() when this function is done, 211 * to end your instrumentation. 212 */ onStart()213 public void onStart() { 214 } 215 216 /** 217 * This is called whenever the system captures an unhandled exception that 218 * was thrown by the application. The default implementation simply 219 * returns false, allowing normal system handling of the exception to take 220 * place. 221 * 222 * @param obj The client object that generated the exception. May be an 223 * Application, Activity, BroadcastReceiver, Service, or null. 224 * @param e The exception that was thrown. 225 * 226 * @return To allow normal system exception process to occur, return false. 227 * If true is returned, the system will proceed as if the exception 228 * didn't happen. 229 */ onException(Object obj, Throwable e)230 public boolean onException(Object obj, Throwable e) { 231 return false; 232 } 233 234 /** 235 * Provide a status report about the application. 236 * 237 * @param resultCode Current success/failure of instrumentation. 238 * @param results Any results to send back to the code that started the instrumentation. 239 */ sendStatus(int resultCode, Bundle results)240 public void sendStatus(int resultCode, Bundle results) { 241 if (mWatcher != null) { 242 try { 243 mWatcher.instrumentationStatus(mComponent, resultCode, results); 244 } 245 catch (RemoteException e) { 246 mWatcher = null; 247 } 248 } 249 } 250 251 /** 252 * Report some results in the middle of instrumentation execution. Later results (including 253 * those provided by {@link #finish}) will be combined with {@link Bundle#putAll}. 254 */ addResults(Bundle results)255 public void addResults(Bundle results) { 256 IActivityManager am = ActivityManager.getService(); 257 try { 258 am.addInstrumentationResults(mThread.getApplicationThread(), results); 259 } catch (RemoteException ex) { 260 throw ex.rethrowFromSystemServer(); 261 } 262 } 263 264 /** 265 * Terminate instrumentation of the application. This will cause the 266 * application process to exit, removing this instrumentation from the next 267 * time the application is started. If multiple processes are currently running 268 * for this instrumentation, all of those processes will be killed. 269 * 270 * @param resultCode Overall success/failure of instrumentation. 271 * @param results Any results to send back to the code that started the 272 * instrumentation. 273 */ finish(int resultCode, Bundle results)274 public void finish(int resultCode, Bundle results) { 275 if (mAutomaticPerformanceSnapshots) { 276 endPerformanceSnapshot(); 277 } 278 if (mPerfMetrics != null) { 279 if (results == null) { 280 results = new Bundle(); 281 } 282 results.putAll(mPerfMetrics); 283 } 284 if ((mUiAutomation != null) && !mUiAutomation.isDestroyed()) { 285 mUiAutomation.disconnect(); 286 mUiAutomation = null; 287 } 288 mThread.finishInstrumentation(resultCode, results); 289 } 290 setAutomaticPerformanceSnapshots()291 public void setAutomaticPerformanceSnapshots() { 292 mAutomaticPerformanceSnapshots = true; 293 mPerformanceCollector = new PerformanceCollector(); 294 } 295 startPerformanceSnapshot()296 public void startPerformanceSnapshot() { 297 if (!isProfiling()) { 298 mPerformanceCollector.beginSnapshot(null); 299 } 300 } 301 endPerformanceSnapshot()302 public void endPerformanceSnapshot() { 303 if (!isProfiling()) { 304 mPerfMetrics = mPerformanceCollector.endSnapshot(); 305 } 306 } 307 308 /** 309 * Called when the instrumented application is stopping, after all of the 310 * normal application cleanup has occurred. 311 */ onDestroy()312 public void onDestroy() { 313 } 314 315 /** 316 * Return the Context of this instrumentation's package. Note that this is 317 * often different than the Context of the application being 318 * instrumentated, since the instrumentation code often lives is a 319 * different package than that of the application it is running against. 320 * See {@link #getTargetContext} to retrieve a Context for the target 321 * application. 322 * 323 * @return The instrumentation's package context. 324 * 325 * @see #getTargetContext 326 */ 327 @android.ravenwood.annotation.RavenwoodKeep getContext()328 public Context getContext() { 329 return mInstrContext; 330 } 331 332 /** 333 * Returns complete component name of this instrumentation. 334 * 335 * @return Returns the complete component name for this instrumentation. 336 */ getComponentName()337 public ComponentName getComponentName() { 338 return mComponent; 339 } 340 341 /** 342 * Return a Context for the target application being instrumented. Note 343 * that this is often different than the Context of the instrumentation 344 * code, since the instrumentation code often lives is a different package 345 * than that of the application it is running against. See 346 * {@link #getContext} to retrieve a Context for the instrumentation code. 347 * 348 * @return A Context in the target application. 349 * 350 * @see #getContext 351 */ 352 @android.ravenwood.annotation.RavenwoodKeep getTargetContext()353 public Context getTargetContext() { 354 return mAppContext; 355 } 356 357 /** 358 * Return the name of the process this instrumentation is running in. Note this should 359 * only be used for testing and debugging. If you are thinking about using this to, 360 * for example, conditionalize what is initialized in an Application class, it is strongly 361 * recommended to instead use lazy initialization (such as a getter for the state that 362 * only creates it when requested). This can greatly reduce the work your process does 363 * when created for secondary things, such as to receive a broadcast. 364 */ getProcessName()365 public String getProcessName() { 366 return mThread.getProcessName(); 367 } 368 369 /** 370 * Check whether this instrumentation was started with profiling enabled. 371 * 372 * @return Returns true if profiling was enabled when starting, else false. 373 */ isProfiling()374 public boolean isProfiling() { 375 return mThread.isProfiling(); 376 } 377 378 /** 379 * This method will start profiling if isProfiling() returns true. You should 380 * only call this method if you set the handleProfiling attribute in the 381 * manifest file for this Instrumentation to true. 382 */ startProfiling()383 public void startProfiling() { 384 if (mThread.isProfiling()) { 385 File file = new File(mThread.getProfileFilePath()); 386 file.getParentFile().mkdirs(); 387 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); 388 } 389 } 390 391 /** 392 * Stops profiling if isProfiling() returns true. 393 */ stopProfiling()394 public void stopProfiling() { 395 if (mThread.isProfiling()) { 396 Debug.stopMethodTracing(); 397 } 398 } 399 400 /** 401 * Force the global system in or out of touch mode. This can be used if your 402 * instrumentation relies on the UI being in one more or the other when it starts. 403 * 404 * <p><b>Note:</b> Starting from Android {@link Build.VERSION_CODES#TIRAMISU}, this method 405 * will only take effect if the instrumentation was sourced from a process with 406 * {@code MODIFY_TOUCH_MODE_STATE} internal permission granted (shell already have it). 407 * 408 * @param inTouch Set to true to be in touch mode, false to be in focus mode. 409 */ setInTouchMode(boolean inTouch)410 public void setInTouchMode(boolean inTouch) { 411 try { 412 IWindowManager.Stub.asInterface( 413 ServiceManager.getService("window")).setInTouchModeOnAllDisplays(inTouch); 414 } catch (RemoteException e) { 415 // Shouldn't happen! 416 } 417 } 418 419 /** 420 * Resets the {@link #setInTouchMode touch mode} to the device default. 421 */ resetInTouchMode()422 public void resetInTouchMode() { 423 final boolean defaultInTouchMode = getContext().getResources().getBoolean( 424 com.android.internal.R.bool.config_defaultInTouchMode); 425 setInTouchMode(defaultInTouchMode); 426 } 427 428 /** 429 * Schedule a callback for when the application's main thread goes idle 430 * (has no more events to process). 431 * 432 * @param recipient Called the next time the thread's message queue is 433 * idle. 434 */ waitForIdle(Runnable recipient)435 public void waitForIdle(Runnable recipient) { 436 mMessageQueue.addIdleHandler(new Idler(recipient)); 437 mThread.getHandler().post(new EmptyRunnable()); 438 } 439 440 /** 441 * Synchronously wait for the application to be idle. Can not be called 442 * from the main application thread -- use {@link #start} to execute 443 * instrumentation in its own thread. 444 */ waitForIdleSync()445 public void waitForIdleSync() { 446 validateNotAppThread(); 447 Idler idler = new Idler(null); 448 mMessageQueue.addIdleHandler(idler); 449 mThread.getHandler().post(new EmptyRunnable()); 450 idler.waitForIdle(); 451 } 452 waitForEnterAnimationComplete(Activity activity)453 private void waitForEnterAnimationComplete(Activity activity) { 454 synchronized (mAnimationCompleteLock) { 455 long timeout = 5000; 456 try { 457 // We need to check that this specified Activity completed the animation, not just 458 // any Activity. If it was another Activity, then decrease the timeout by how long 459 // it's already waited and wait for the thread to wakeup again. 460 while (timeout > 0 && !activity.mEnterAnimationComplete) { 461 long startTime = System.currentTimeMillis(); 462 mAnimationCompleteLock.wait(timeout); 463 long totalTime = System.currentTimeMillis() - startTime; 464 timeout -= totalTime; 465 } 466 } catch (InterruptedException e) { 467 } 468 } 469 } 470 471 /** @hide */ onEnterAnimationComplete()472 public void onEnterAnimationComplete() { 473 synchronized (mAnimationCompleteLock) { 474 mAnimationCompleteLock.notifyAll(); 475 } 476 } 477 478 /** 479 * Execute a call on the application's main thread, blocking until it is 480 * complete. Useful for doing things that are not thread-safe, such as 481 * looking at or modifying the view hierarchy. 482 * 483 * @param runner The code to run on the main thread. 484 */ runOnMainSync(Runnable runner)485 public void runOnMainSync(Runnable runner) { 486 validateNotAppThread(); 487 SyncRunnable sr = new SyncRunnable(runner); 488 mThread.getHandler().post(sr); 489 sr.waitForComplete(); 490 } 491 isSdkSandboxAllowedToStartActivities()492 boolean isSdkSandboxAllowedToStartActivities() { 493 return Process.isSdkSandbox() 494 && mThread != null 495 && mThread.mBoundApplication != null 496 && mThread.mBoundApplication.isSdkInSandbox 497 && getContext() != null 498 && (getContext() 499 .checkSelfPermission( 500 android.Manifest.permission 501 .START_ACTIVITIES_FROM_SDK_SANDBOX) 502 == PackageManager.PERMISSION_GRANTED); 503 } 504 505 /** 506 * Activity name resolution for CTS-in-SdkSandbox tests requires some adjustments. Intents 507 * generated using {@link Context#getPackageName()} use the SDK sandbox package name in the 508 * component field instead of the test package name. An SDK-in-sandbox test attempting to launch 509 * an activity in the test package will encounter name resolution errors when resolving the 510 * activity name in the SDK sandbox package. 511 * 512 * <p>This function replaces the package name of the input intent component to allow activities 513 * belonging to a CTS-in-sandbox test to resolve correctly. 514 * 515 * @param intent the intent to modify to allow CTS-in-sandbox activity resolution. 516 */ adjustIntentForCtsInSdkSandboxInstrumentation(@onNull Intent intent)517 private void adjustIntentForCtsInSdkSandboxInstrumentation(@NonNull Intent intent) { 518 if (mComponent != null 519 && intent.getComponent() != null 520 && getContext() 521 .getPackageManager() 522 .getSdkSandboxPackageName() 523 .equals(intent.getComponent().getPackageName())) { 524 // Resolve the intent target for the test package, not for the sandbox package. 525 intent.setComponent( 526 new ComponentName( 527 mComponent.getPackageName(), intent.getComponent().getClassName())); 528 } 529 // We match the intent identifier against the running instrumentations for the sandbox. 530 intent.setIdentifier(mComponent.getPackageName()); 531 } 532 resolveActivityInfoForCtsInSandbox(@onNull Intent intent)533 private ActivityInfo resolveActivityInfoForCtsInSandbox(@NonNull Intent intent) { 534 adjustIntentForCtsInSdkSandboxInstrumentation(intent); 535 ActivityInfo ai = intent.resolveActivityInfo(getTargetContext().getPackageManager(), 0); 536 if (ai != null) { 537 ai.processName = mThread.getProcessName(); 538 } 539 return ai; 540 } 541 542 /** 543 * Start a new activity and wait for it to begin running before returning. 544 * In addition to being synchronous, this method as some semantic 545 * differences from the standard {@link Context#startActivity} call: the 546 * activity component is resolved before talking with the activity manager 547 * (its class name is specified in the Intent that this method ultimately 548 * starts), and it does not allow you to start activities that run in a 549 * different process. In addition, if the given Intent resolves to 550 * multiple activities, instead of displaying a dialog for the user to 551 * select an activity, an exception will be thrown. 552 * 553 * <p>The function returns as soon as the activity goes idle following the 554 * call to its {@link Activity#onCreate}. Generally this means it has gone 555 * through the full initialization including {@link Activity#onResume} and 556 * drawn and displayed its initial window. 557 * 558 * @param intent Description of the activity to start. 559 * 560 * @see Context#startActivity 561 * @see #startActivitySync(Intent, Bundle) 562 */ startActivitySync(Intent intent)563 public Activity startActivitySync(Intent intent) { 564 return startActivitySync(intent, null /* options */); 565 } 566 567 /** 568 * Start a new activity and wait for it to begin running before returning. 569 * In addition to being synchronous, this method as some semantic 570 * differences from the standard {@link Context#startActivity} call: the 571 * activity component is resolved before talking with the activity manager 572 * (its class name is specified in the Intent that this method ultimately 573 * starts), and it does not allow you to start activities that run in a 574 * different process. In addition, if the given Intent resolves to 575 * multiple activities, instead of displaying a dialog for the user to 576 * select an activity, an exception will be thrown. 577 * 578 * <p>The function returns as soon as the activity goes idle following the 579 * call to its {@link Activity#onCreate}. Generally this means it has gone 580 * through the full initialization including {@link Activity#onResume} and 581 * drawn and displayed its initial window. 582 * 583 * @param intent Description of the activity to start. 584 * @param options Additional options for how the Activity should be started. 585 * May be null if there are no options. See {@link android.app.ActivityOptions} 586 * for how to build the Bundle supplied here; there are no supported definitions 587 * for building it manually. 588 * 589 * @see Context#startActivity(Intent, Bundle) 590 */ 591 @NonNull startActivitySync(@onNull Intent intent, @Nullable Bundle options)592 public Activity startActivitySync(@NonNull Intent intent, @Nullable Bundle options) { 593 if (DEBUG_START_ACTIVITY) { 594 Log.d(TAG, "startActivity: intent=" + intent + " options=" + options, new Throwable()); 595 } 596 validateNotAppThread(); 597 598 final Activity activity; 599 synchronized (mSync) { 600 intent = new Intent(intent); 601 602 ActivityInfo ai = 603 isSdkSandboxAllowedToStartActivities() 604 ? resolveActivityInfoForCtsInSandbox(intent) 605 : intent.resolveActivityInfo(getTargetContext().getPackageManager(), 0); 606 if (ai == null) { 607 throw new RuntimeException("Unable to resolve activity for: " + intent); 608 } 609 String myProc = mThread.getProcessName(); 610 if (!ai.processName.equals(myProc)) { 611 // todo: if this intent is ambiguous, look here to see if 612 // there is a single match that is in our package. 613 throw new RuntimeException("Intent in process " 614 + myProc + " resolved to different process " 615 + ai.processName + ": " + intent); 616 } 617 618 intent.setComponent(new ComponentName( 619 ai.applicationInfo.packageName, ai.name)); 620 final ActivityWaiter aw = new ActivityWaiter(intent); 621 622 if (mWaitingActivities == null) { 623 mWaitingActivities = new ArrayList(); 624 } 625 mWaitingActivities.add(aw); 626 627 getTargetContext().startActivity(intent, options); 628 629 do { 630 try { 631 mSync.wait(); 632 } catch (InterruptedException e) { 633 } 634 } while (mWaitingActivities.contains(aw)); 635 activity = aw.activity; 636 } 637 638 // Do not call this method within mSync, lest it could block the main thread. 639 waitForEnterAnimationComplete(activity); 640 641 // Apply an empty transaction to ensure SF has a chance to update before 642 // the Activity is ready (b/138263890). 643 try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) { 644 t.apply(true); 645 } 646 return activity; 647 } 648 649 /** 650 * Information about a particular kind of Intent that is being monitored. 651 * An instance of this class is added to the 652 * current instrumentation through {@link #addMonitor}; after being added, 653 * when a new activity is being started the monitor will be checked and, if 654 * matching, its hit count updated and (optionally) the call stopped and a 655 * canned result returned. 656 * 657 * <p>An ActivityMonitor can also be used to look for the creation of an 658 * activity, through the {@link #waitForActivity} method. This will return 659 * after a matching activity has been created with that activity object. 660 */ 661 public static class ActivityMonitor { 662 private final IntentFilter mWhich; 663 private final String mClass; 664 private final ActivityResult mResult; 665 private final boolean mBlock; 666 private final boolean mIgnoreMatchingSpecificIntents; 667 668 669 // This is protected by 'Instrumentation.this.mSync'. 670 /*package*/ int mHits = 0; 671 672 // This is protected by 'this'. 673 /*package*/ Activity mLastActivity = null; 674 675 /** 676 * Create a new ActivityMonitor that looks for a particular kind of 677 * intent to be started. 678 * 679 * @param which The set of intents this monitor is responsible for. 680 * @param result A canned result to return if the monitor is hit; can 681 * be null. 682 * @param block Controls whether the monitor should block the activity 683 * start (returning its canned result) or let the call 684 * proceed. 685 * 686 * @see Instrumentation#addMonitor 687 */ ActivityMonitor( IntentFilter which, ActivityResult result, boolean block)688 public ActivityMonitor( 689 IntentFilter which, ActivityResult result, boolean block) { 690 mWhich = which; 691 mClass = null; 692 mResult = result; 693 mBlock = block; 694 mIgnoreMatchingSpecificIntents = false; 695 } 696 697 /** 698 * Create a new ActivityMonitor that looks for a specific activity 699 * class to be started. 700 * 701 * @param cls The activity class this monitor is responsible for. 702 * @param result A canned result to return if the monitor is hit; can 703 * be null. 704 * @param block Controls whether the monitor should block the activity 705 * start (returning its canned result) or let the call 706 * proceed. 707 * 708 * @see Instrumentation#addMonitor 709 */ ActivityMonitor( String cls, ActivityResult result, boolean block)710 public ActivityMonitor( 711 String cls, ActivityResult result, boolean block) { 712 mWhich = null; 713 mClass = cls; 714 mResult = result; 715 mBlock = block; 716 mIgnoreMatchingSpecificIntents = false; 717 } 718 719 /** 720 * Create a new ActivityMonitor that can be used for intercepting any activity to be 721 * started. 722 * 723 * <p> When an activity is started, {@link #onStartActivity(Intent)} will be called on 724 * instances created using this constructor to see if it is a hit. 725 * 726 * @see #onStartActivity(Intent) 727 */ ActivityMonitor()728 public ActivityMonitor() { 729 mWhich = null; 730 mClass = null; 731 mResult = null; 732 mBlock = false; 733 mIgnoreMatchingSpecificIntents = true; 734 } 735 736 /** 737 * @return true if this monitor is used for intercepting any started activity by calling 738 * into {@link #onStartActivity(Intent)}, false if this monitor is only used 739 * for specific intents corresponding to the intent filter or activity class 740 * passed in the constructor. 741 */ ignoreMatchingSpecificIntents()742 final boolean ignoreMatchingSpecificIntents() { 743 return mIgnoreMatchingSpecificIntents; 744 } 745 746 /** 747 * Retrieve the filter associated with this ActivityMonitor. 748 */ getFilter()749 public final IntentFilter getFilter() { 750 return mWhich; 751 } 752 753 /** 754 * Retrieve the result associated with this ActivityMonitor, or null if 755 * none. 756 */ getResult()757 public final ActivityResult getResult() { 758 return mResult; 759 } 760 761 /** 762 * Check whether this monitor blocks activity starts (not allowing the 763 * actual activity to run) or allows them to execute normally. 764 */ isBlocking()765 public final boolean isBlocking() { 766 return mBlock; 767 } 768 769 /** 770 * Retrieve the number of times the monitor has been hit so far. 771 */ getHits()772 public final int getHits() { 773 return mHits; 774 } 775 776 /** 777 * Retrieve the most recent activity class that was seen by this 778 * monitor. 779 */ getLastActivity()780 public final Activity getLastActivity() { 781 return mLastActivity; 782 } 783 784 /** 785 * Block until an Activity is created that matches this monitor, 786 * returning the resulting activity. 787 * 788 * @return Activity 789 */ waitForActivity()790 public final Activity waitForActivity() { 791 synchronized (this) { 792 while (mLastActivity == null) { 793 try { 794 wait(); 795 } catch (InterruptedException e) { 796 } 797 } 798 Activity res = mLastActivity; 799 mLastActivity = null; 800 return res; 801 } 802 } 803 804 /** 805 * Block until an Activity is created that matches this monitor, 806 * returning the resulting activity or till the timeOut period expires. 807 * If the timeOut expires before the activity is started, return null. 808 * 809 * @param timeOut Time to wait in milliseconds before the activity is created. 810 * 811 * @return Activity 812 */ waitForActivityWithTimeout(long timeOut)813 public final Activity waitForActivityWithTimeout(long timeOut) { 814 synchronized (this) { 815 if (mLastActivity == null) { 816 try { 817 wait(timeOut); 818 } catch (InterruptedException e) { 819 } 820 } 821 if (mLastActivity == null) { 822 return null; 823 } else { 824 Activity res = mLastActivity; 825 mLastActivity = null; 826 return res; 827 } 828 } 829 } 830 831 /** 832 * This overload is used for notifying the {@link android.window.TaskFragmentOrganizer} 833 * implementation internally about started activities. 834 * 835 * @see #onStartActivity(Intent) 836 * @hide 837 */ onStartActivity(@onNull Context who, @NonNull Intent intent, @NonNull Bundle options)838 public ActivityResult onStartActivity(@NonNull Context who, @NonNull Intent intent, 839 @NonNull Bundle options) { 840 return onStartActivity(intent); 841 } 842 843 /** 844 * Used for intercepting any started activity. 845 * 846 * <p> A non-null return value here will be considered a hit for this monitor. 847 * By default this will return {@code null} and subclasses can override this to return 848 * a non-null value if the intent needs to be intercepted. 849 * 850 * <p> Whenever a new activity is started, this method will be called on instances created 851 * using {@link #ActivityMonitor()} to check if there is a match. In case 852 * of a match, the activity start will be blocked and the returned result will be used. 853 * 854 * @param intent The intent used for starting the activity. 855 * @return The {@link ActivityResult} that needs to be used in case of a match. 856 */ onStartActivity(Intent intent)857 public ActivityResult onStartActivity(Intent intent) { 858 return null; 859 } 860 861 /** 862 * This is called after starting an Activity and provides the result code that defined in 863 * {@link ActivityManager}, like {@link ActivityManager#START_SUCCESS}. 864 * 865 * @param result the result code that returns after starting an Activity. 866 * @param bOptions the bundle generated from {@link ActivityOptions} that originally 867 * being used to start the Activity. 868 * @hide 869 */ onStartActivityResult(int result, @NonNull Bundle bOptions)870 public void onStartActivityResult(int result, @NonNull Bundle bOptions) {} 871 match(Context who, Activity activity, Intent intent)872 final boolean match(Context who, 873 Activity activity, 874 Intent intent) { 875 if (mIgnoreMatchingSpecificIntents) { 876 return false; 877 } 878 synchronized (this) { 879 if (mWhich != null 880 && mWhich.match(who.getContentResolver(), intent, 881 true, "Instrumentation") < 0) { 882 return false; 883 } 884 if (mClass != null) { 885 String cls = null; 886 if (activity != null) { 887 cls = activity.getClass().getName(); 888 } else if (intent.getComponent() != null) { 889 cls = intent.getComponent().getClassName(); 890 } 891 if (cls == null || !mClass.equals(cls)) { 892 return false; 893 } 894 } 895 if (activity != null) { 896 mLastActivity = activity; 897 notifyAll(); 898 } 899 return true; 900 } 901 } 902 } 903 904 /** 905 * Add a new {@link ActivityMonitor} that will be checked whenever an 906 * activity is started. The monitor is added 907 * after any existing ones; the monitor will be hit only if none of the 908 * existing monitors can themselves handle the Intent. 909 * 910 * @param monitor The new ActivityMonitor to see. 911 * 912 * @see #addMonitor(IntentFilter, ActivityResult, boolean) 913 * @see #checkMonitorHit 914 */ addMonitor(ActivityMonitor monitor)915 public void addMonitor(ActivityMonitor monitor) { 916 synchronized (mSync) { 917 if (mActivityMonitors == null) { 918 mActivityMonitors = new ArrayList(); 919 } 920 mActivityMonitors.add(monitor); 921 } 922 } 923 924 /** 925 * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that 926 * creates an intent filter matching {@link ActivityMonitor} for you and 927 * returns it. 928 * 929 * @param filter The set of intents this monitor is responsible for. 930 * @param result A canned result to return if the monitor is hit; can 931 * be null. 932 * @param block Controls whether the monitor should block the activity 933 * start (returning its canned result) or let the call 934 * proceed. 935 * 936 * @return The newly created and added activity monitor. 937 * 938 * @see #addMonitor(ActivityMonitor) 939 * @see #checkMonitorHit 940 */ addMonitor( IntentFilter filter, ActivityResult result, boolean block)941 public ActivityMonitor addMonitor( 942 IntentFilter filter, ActivityResult result, boolean block) { 943 ActivityMonitor am = new ActivityMonitor(filter, result, block); 944 addMonitor(am); 945 return am; 946 } 947 948 /** 949 * A convenience wrapper for {@link #addMonitor(ActivityMonitor)} that 950 * creates a class matching {@link ActivityMonitor} for you and returns it. 951 * 952 * @param cls The activity class this monitor is responsible for. 953 * @param result A canned result to return if the monitor is hit; can 954 * be null. 955 * @param block Controls whether the monitor should block the activity 956 * start (returning its canned result) or let the call 957 * proceed. 958 * 959 * @return The newly created and added activity monitor. 960 * 961 * @see #addMonitor(ActivityMonitor) 962 * @see #checkMonitorHit 963 */ addMonitor( String cls, ActivityResult result, boolean block)964 public ActivityMonitor addMonitor( 965 String cls, ActivityResult result, boolean block) { 966 ActivityMonitor am = new ActivityMonitor(cls, result, block); 967 addMonitor(am); 968 return am; 969 } 970 971 /** 972 * Test whether an existing {@link ActivityMonitor} has been hit. If the 973 * monitor has been hit at least <var>minHits</var> times, then it will be 974 * removed from the activity monitor list and true returned. Otherwise it 975 * is left as-is and false is returned. 976 * 977 * @param monitor The ActivityMonitor to check. 978 * @param minHits The minimum number of hits required. 979 * 980 * @return True if the hit count has been reached, else false. 981 * 982 * @see #addMonitor 983 */ checkMonitorHit(ActivityMonitor monitor, int minHits)984 public boolean checkMonitorHit(ActivityMonitor monitor, int minHits) { 985 waitForIdleSync(); 986 synchronized (mSync) { 987 if (monitor.getHits() < minHits) { 988 return false; 989 } 990 mActivityMonitors.remove(monitor); 991 } 992 return true; 993 } 994 995 /** 996 * Wait for an existing {@link ActivityMonitor} to be hit. Once the 997 * monitor has been hit, it is removed from the activity monitor list and 998 * the first created Activity object that matched it is returned. 999 * 1000 * @param monitor The ActivityMonitor to wait for. 1001 * 1002 * @return The Activity object that matched the monitor. 1003 */ waitForMonitor(ActivityMonitor monitor)1004 public Activity waitForMonitor(ActivityMonitor monitor) { 1005 Activity activity = monitor.waitForActivity(); 1006 synchronized (mSync) { 1007 mActivityMonitors.remove(monitor); 1008 } 1009 return activity; 1010 } 1011 1012 /** 1013 * Wait for an existing {@link ActivityMonitor} to be hit till the timeout 1014 * expires. Once the monitor has been hit, it is removed from the activity 1015 * monitor list and the first created Activity object that matched it is 1016 * returned. If the timeout expires, a null object is returned. 1017 * 1018 * @param monitor The ActivityMonitor to wait for. 1019 * @param timeOut The timeout value in milliseconds. 1020 * 1021 * @return The Activity object that matched the monitor. 1022 */ waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut)1023 public Activity waitForMonitorWithTimeout(ActivityMonitor monitor, long timeOut) { 1024 Activity activity = monitor.waitForActivityWithTimeout(timeOut); 1025 synchronized (mSync) { 1026 mActivityMonitors.remove(monitor); 1027 } 1028 return activity; 1029 } 1030 1031 /** 1032 * Remove an {@link ActivityMonitor} that was previously added with 1033 * {@link #addMonitor}. 1034 * 1035 * @param monitor The monitor to remove. 1036 * 1037 * @see #addMonitor 1038 */ removeMonitor(ActivityMonitor monitor)1039 public void removeMonitor(ActivityMonitor monitor) { 1040 synchronized (mSync) { 1041 mActivityMonitors.remove(monitor); 1042 } 1043 } 1044 1045 /** 1046 * Execute a particular menu item. 1047 * 1048 * @param targetActivity The activity in question. 1049 * @param id The identifier associated with the menu item. 1050 * @param flag Additional flags, if any. 1051 * @return Whether the invocation was successful (for example, it could be 1052 * false if item is disabled). 1053 */ invokeMenuActionSync(Activity targetActivity, int id, int flag)1054 public boolean invokeMenuActionSync(Activity targetActivity, 1055 int id, int flag) { 1056 class MenuRunnable implements Runnable { 1057 private final Activity activity; 1058 private final int identifier; 1059 private final int flags; 1060 boolean returnValue; 1061 1062 public MenuRunnable(Activity _activity, int _identifier, 1063 int _flags) { 1064 activity = _activity; 1065 identifier = _identifier; 1066 flags = _flags; 1067 } 1068 1069 public void run() { 1070 Window win = activity.getWindow(); 1071 1072 returnValue = win.performPanelIdentifierAction( 1073 Window.FEATURE_OPTIONS_PANEL, 1074 identifier, 1075 flags); 1076 } 1077 1078 } 1079 MenuRunnable mr = new MenuRunnable(targetActivity, id, flag); 1080 runOnMainSync(mr); 1081 return mr.returnValue; 1082 } 1083 1084 /** 1085 * Show the context menu for the currently focused view and executes a 1086 * particular context menu item. 1087 * 1088 * @param targetActivity The activity in question. 1089 * @param id The identifier associated with the context menu item. 1090 * @param flag Additional flags, if any. 1091 * @return Whether the invocation was successful (for example, it could be 1092 * false if item is disabled). 1093 */ invokeContextMenuAction(Activity targetActivity, int id, int flag)1094 public boolean invokeContextMenuAction(Activity targetActivity, int id, int flag) { 1095 validateNotAppThread(); 1096 1097 // Bring up context menu for current focus. 1098 // It'd be nice to do this through code, but currently ListView depends on 1099 // long press to set metadata for its selected child 1100 1101 final KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER); 1102 sendKeySync(downEvent); 1103 1104 // Need to wait for long press 1105 waitForIdleSync(); 1106 try { 1107 Thread.sleep(ViewConfiguration.getLongPressTimeout()); 1108 } catch (InterruptedException e) { 1109 Log.e(TAG, "Could not sleep for long press timeout", e); 1110 return false; 1111 } 1112 1113 final KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER); 1114 sendKeySync(upEvent); 1115 1116 // Wait for context menu to appear 1117 waitForIdleSync(); 1118 1119 class ContextMenuRunnable implements Runnable { 1120 private final Activity activity; 1121 private final int identifier; 1122 private final int flags; 1123 boolean returnValue; 1124 1125 public ContextMenuRunnable(Activity _activity, int _identifier, 1126 int _flags) { 1127 activity = _activity; 1128 identifier = _identifier; 1129 flags = _flags; 1130 } 1131 1132 public void run() { 1133 Window win = activity.getWindow(); 1134 returnValue = win.performContextMenuIdentifierAction( 1135 identifier, 1136 flags); 1137 } 1138 1139 } 1140 1141 ContextMenuRunnable cmr = new ContextMenuRunnable(targetActivity, id, flag); 1142 runOnMainSync(cmr); 1143 return cmr.returnValue; 1144 } 1145 1146 /** 1147 * Sends the key events that result in the given text being typed into the currently focused 1148 * window, and waits for it to be processed. 1149 * 1150 * @param text The text to be sent. 1151 * @see #sendKeySync(KeyEvent) 1152 */ sendStringSync(String text)1153 public void sendStringSync(String text) { 1154 if (text == null) { 1155 return; 1156 } 1157 KeyCharacterMap keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); 1158 1159 KeyEvent[] events = keyCharacterMap.getEvents(text.toCharArray()); 1160 1161 if (events != null) { 1162 for (int i = 0; i < events.length; i++) { 1163 // We have to change the time of an event before injecting it because 1164 // all KeyEvents returned by KeyCharacterMap.getEvents() have the same 1165 // time stamp and the system rejects too old events. Hence, it is 1166 // possible for an event to become stale before it is injected if it 1167 // takes too long to inject the preceding ones. 1168 sendKeySync(KeyEvent.changeTimeRepeat(events[i], SystemClock.uptimeMillis(), 0)); 1169 } 1170 } 1171 } 1172 1173 /** 1174 * Sends a key event to the currently focused window, and waits for it to be processed. 1175 * <p> 1176 * This method blocks until the recipient has finished handling the event. Note that the 1177 * recipient may <em>not</em> have completely finished reacting from the event when this method 1178 * returns. For example, it may still be in the process of updating its display or UI contents 1179 * upon reacting to the injected event. 1180 * 1181 * @param event The event to send to the current focus. 1182 */ sendKeySync(KeyEvent event)1183 public void sendKeySync(KeyEvent event) { 1184 validateNotAppThread(); 1185 1186 long downTime = event.getDownTime(); 1187 long eventTime = event.getEventTime(); 1188 int source = event.getSource(); 1189 if (source == InputDevice.SOURCE_UNKNOWN) { 1190 source = InputDevice.SOURCE_KEYBOARD; 1191 } 1192 if (eventTime == 0) { 1193 eventTime = SystemClock.uptimeMillis(); 1194 } 1195 if (downTime == 0) { 1196 downTime = eventTime; 1197 } 1198 KeyEvent newEvent = new KeyEvent(event); 1199 newEvent.setTime(downTime, eventTime); 1200 newEvent.setSource(source); 1201 newEvent.setFlags(event.getFlags() | KeyEvent.FLAG_FROM_SYSTEM); 1202 setDisplayIfNeeded(newEvent); 1203 1204 InputManagerGlobal.getInstance().injectInputEvent(newEvent, 1205 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 1206 } 1207 setDisplayIfNeeded(KeyEvent event)1208 private void setDisplayIfNeeded(KeyEvent event) { 1209 if (!UserManager.isVisibleBackgroundUsersEnabled()) { 1210 return; 1211 } 1212 // In devices that support visible background users visible, the display id must be set to 1213 // reflect the display the user was started visible on, otherwise the event would be sent to 1214 // the main display (which would most likely fail the test). 1215 int eventDisplayId = event.getDisplayId(); 1216 if (eventDisplayId != Display.INVALID_DISPLAY) { 1217 if (VERBOSE) { 1218 Log.v(TAG, "setDisplayIfNeeded(" + event + "): not changing display id as it's " 1219 + "explicitly set to " + eventDisplayId); 1220 } 1221 return; 1222 } 1223 1224 UserManager userManager = mInstrContext.getSystemService(UserManager.class); 1225 int userDisplayId = userManager.getMainDisplayIdAssignedToUser(); 1226 if (VERBOSE) { 1227 Log.v(TAG, "setDisplayIfNeeded(" + event + "): eventDisplayId=" + eventDisplayId 1228 + ", user=" + mInstrContext.getUser() + ", userDisplayId=" + userDisplayId); 1229 } 1230 if (userDisplayId == Display.INVALID_DISPLAY) { 1231 Log.e(TAG, "setDisplayIfNeeded(" + event + "): UserManager returned INVALID_DISPLAY as " 1232 + "display assigned to user " + mInstrContext.getUser()); 1233 return; 1234 1235 } 1236 1237 event.setDisplayId(userDisplayId); 1238 } 1239 1240 /** 1241 * Sends up and down key events with the given key code to the currently focused window, and 1242 * waits for it to be processed. 1243 * 1244 * @param keyCode The key code for the events to send. 1245 * @see #sendKeySync(KeyEvent) 1246 */ sendKeyDownUpSync(int keyCode)1247 public void sendKeyDownUpSync(int keyCode) { 1248 sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)); 1249 sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode)); 1250 } 1251 1252 /** 1253 * Sends up and down key events with the given key code to the currently focused window, and 1254 * waits for it to be processed. 1255 * <p> 1256 * Equivalent to {@link #sendKeyDownUpSync(int)}. 1257 * 1258 * @param keyCode The key code of the character to send. 1259 * @see #sendKeySync(KeyEvent) 1260 */ sendCharacterSync(int keyCode)1261 public void sendCharacterSync(int keyCode) { 1262 sendKeyDownUpSync(keyCode); 1263 } 1264 1265 /** 1266 * Dispatches a pointer event into a window owned by the instrumented application, and waits for 1267 * it to be processed. 1268 * <p> 1269 * If the motion event being injected is targeted at a window that is not owned by the 1270 * instrumented application, the input injection will fail. See {@link #getUiAutomation()} for 1271 * injecting events into all windows. 1272 * <p> 1273 * This method blocks until the recipient has finished handling the event. Note that the 1274 * recipient may <em>not</em> have completely finished reacting from the event when this method 1275 * returns. For example, it may still be in the process of updating its display or UI contents 1276 * upon reacting to the injected event. 1277 * 1278 * @param event A motion event describing the pointer action. (As noted in 1279 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use 1280 * {@link SystemClock#uptimeMillis()} as the timebase. 1281 */ sendPointerSync(MotionEvent event)1282 public void sendPointerSync(MotionEvent event) { 1283 validateNotAppThread(); 1284 if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) { 1285 event.setSource(InputDevice.SOURCE_TOUCHSCREEN); 1286 } 1287 1288 syncInputTransactionsAndInjectEventIntoSelf(event); 1289 } 1290 syncInputTransactionsAndInjectEventIntoSelf(MotionEvent event)1291 private void syncInputTransactionsAndInjectEventIntoSelf(MotionEvent event) { 1292 final boolean syncBefore = event.getAction() == MotionEvent.ACTION_DOWN 1293 || event.isFromSource(InputDevice.SOURCE_MOUSE); 1294 final boolean syncAfter = event.getAction() == MotionEvent.ACTION_UP; 1295 1296 try { 1297 if (syncBefore) { 1298 WindowManagerGlobal.getWindowManagerService() 1299 .syncInputTransactions(true /*waitForAnimations*/); 1300 } 1301 1302 // Direct the injected event into windows owned by the instrumentation target. 1303 InputManagerGlobal.getInstance().injectInputEvent( 1304 event, InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH, Process.myUid()); 1305 1306 if (syncAfter) { 1307 WindowManagerGlobal.getWindowManagerService() 1308 .syncInputTransactions(true /*waitForAnimations*/); 1309 } 1310 } catch (RemoteException e) { 1311 e.rethrowFromSystemServer(); 1312 } 1313 } 1314 1315 /** 1316 * Dispatches a trackball event into the currently focused window, and waits for it to be 1317 * processed. 1318 * <p> 1319 * This method blocks until the recipient has finished handling the event. Note that the 1320 * recipient may <em>not</em> have completely finished reacting from the event when this method 1321 * returns. For example, it may still be in the process of updating its display or UI contents 1322 * upon reacting to the injected event. 1323 * 1324 * @param event A motion event describing the trackball action. (As noted in 1325 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use 1326 * {@link SystemClock#uptimeMillis()} as the timebase. 1327 */ sendTrackballEventSync(MotionEvent event)1328 public void sendTrackballEventSync(MotionEvent event) { 1329 validateNotAppThread(); 1330 if (!event.isFromSource(InputDevice.SOURCE_CLASS_TRACKBALL)) { 1331 event.setSource(InputDevice.SOURCE_TRACKBALL); 1332 } 1333 InputManagerGlobal.getInstance().injectInputEvent(event, 1334 InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH); 1335 } 1336 1337 /** 1338 * Perform instantiation of the process's {@link Application} object. The 1339 * default implementation provides the normal system behavior. 1340 * 1341 * @param cl The ClassLoader with which to instantiate the object. 1342 * @param className The name of the class implementing the Application 1343 * object. 1344 * @param context The context to initialize the application with 1345 * 1346 * @return The newly instantiated Application object. 1347 */ newApplication(ClassLoader cl, String className, Context context)1348 public Application newApplication(ClassLoader cl, String className, Context context) 1349 throws InstantiationException, IllegalAccessException, 1350 ClassNotFoundException { 1351 Application app = getFactory(context.getPackageName()) 1352 .instantiateApplication(cl, className); 1353 app.attach(context); 1354 return app; 1355 } 1356 1357 /** 1358 * Perform instantiation of the process's {@link Application} object. The 1359 * default implementation provides the normal system behavior. 1360 * 1361 * @param clazz The class used to create an Application object from. 1362 * @param context The context to initialize the application with 1363 * 1364 * @return The newly instantiated Application object. 1365 */ newApplication(Class<?> clazz, Context context)1366 static public Application newApplication(Class<?> clazz, Context context) 1367 throws InstantiationException, IllegalAccessException, 1368 ClassNotFoundException { 1369 Application app = (Application)clazz.newInstance(); 1370 app.attach(context); 1371 return app; 1372 } 1373 1374 /** 1375 * Perform calling of the application's {@link Application#onCreate} 1376 * method. The default implementation simply calls through to that method. 1377 * 1378 * <p>Note: This method will be called immediately after {@link #onCreate(Bundle)}. 1379 * Often instrumentation tests start their test thread in onCreate(); you 1380 * need to be careful of races between these. (Well between it and 1381 * everything else, but let's start here.) 1382 * 1383 * @param app The application being created. 1384 */ callApplicationOnCreate(Application app)1385 public void callApplicationOnCreate(Application app) { 1386 app.onCreate(); 1387 } 1388 1389 /** 1390 * Perform instantiation of an {@link Activity} object. This method is intended for use with 1391 * unit tests, such as android.test.ActivityUnitTestCase. The activity will be useable 1392 * locally but will be missing some of the linkages necessary for use within the system. 1393 * 1394 * @param clazz The Class of the desired Activity 1395 * @param context The base context for the activity to use 1396 * @param token The token for this activity to communicate with 1397 * @param application The application object (if any) 1398 * @param intent The intent that started this Activity 1399 * @param info ActivityInfo from the manifest 1400 * @param title The title, typically retrieved from the ActivityInfo record 1401 * @param parent The parent Activity (if any) 1402 * @param id The embedded Id (if any) 1403 * @param lastNonConfigurationInstance Arbitrary object that will be 1404 * available via {@link Activity#getLastNonConfigurationInstance() 1405 * Activity.getLastNonConfigurationInstance()}. 1406 * @return Returns the instantiated activity 1407 * @throws InstantiationException 1408 * @throws IllegalAccessException 1409 */ newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance)1410 public Activity newActivity(Class<?> clazz, Context context, 1411 IBinder token, Application application, Intent intent, ActivityInfo info, 1412 CharSequence title, Activity parent, String id, 1413 Object lastNonConfigurationInstance) throws InstantiationException, 1414 IllegalAccessException { 1415 Activity activity = (Activity)clazz.newInstance(); 1416 ActivityThread aThread = null; 1417 // Activity.attach expects a non-null Application Object. 1418 if (application == null) { 1419 application = new Application(); 1420 } 1421 activity.attach(context, aThread, this, token, 0 /* ident */, application, intent, 1422 info, title, parent, id, 1423 (Activity.NonConfigurationInstances)lastNonConfigurationInstance, 1424 new Configuration(), null /* referrer */, null /* voiceInteractor */, 1425 null /* window */, null /* activityCallback */, null /* assistToken */, 1426 null /* shareableActivityToken */, null /* initialCallerInfoAccessToken */); 1427 return activity; 1428 } 1429 1430 /** 1431 * Perform instantiation of the process's {@link Activity} object. The 1432 * default implementation provides the normal system behavior. 1433 * 1434 * @param cl The ClassLoader with which to instantiate the object. 1435 * @param className The name of the class implementing the Activity 1436 * object. 1437 * @param intent The Intent object that specified the activity class being 1438 * instantiated. 1439 * 1440 * @return The newly instantiated Activity object. 1441 */ newActivity(ClassLoader cl, String className, Intent intent)1442 public Activity newActivity(ClassLoader cl, String className, 1443 Intent intent) 1444 throws InstantiationException, IllegalAccessException, 1445 ClassNotFoundException { 1446 String pkg = intent != null && intent.getComponent() != null 1447 ? intent.getComponent().getPackageName() : null; 1448 return getFactory(pkg).instantiateActivity(cl, className, intent); 1449 } 1450 getFactory(String pkg)1451 private AppComponentFactory getFactory(String pkg) { 1452 if (pkg == null) { 1453 Log.e(TAG, "No pkg specified, disabling AppComponentFactory"); 1454 return AppComponentFactory.DEFAULT; 1455 } 1456 if (mThread == null) { 1457 Log.e(TAG, "Uninitialized ActivityThread, likely app-created Instrumentation," 1458 + " disabling AppComponentFactory", new Throwable()); 1459 return AppComponentFactory.DEFAULT; 1460 } 1461 LoadedApk apk = mThread.peekPackageInfo(pkg, true); 1462 // This is in the case of starting up "android". 1463 if (apk == null) apk = mThread.getSystemContext().mPackageInfo; 1464 return apk.getAppFactory(); 1465 } 1466 1467 /** 1468 * This should be called before {@link #checkStartActivityResult(int, Object)}, because 1469 * exceptions might be thrown while checking the results. 1470 */ notifyStartActivityResult(int result, @Nullable Bundle options)1471 private void notifyStartActivityResult(int result, @Nullable Bundle options) { 1472 if (mActivityMonitors == null) { 1473 return; 1474 } 1475 synchronized (mSync) { 1476 final int size = mActivityMonitors.size(); 1477 for (int i = 0; i < size; i++) { 1478 final ActivityMonitor am = mActivityMonitors.get(i); 1479 if (am.ignoreMatchingSpecificIntents()) { 1480 if (options == null) { 1481 options = ActivityOptions.makeBasic().toBundle(); 1482 } 1483 am.onStartActivityResult(result, options); 1484 } 1485 } 1486 } 1487 } 1488 prePerformCreate(Activity activity)1489 private void prePerformCreate(Activity activity) { 1490 if (mWaitingActivities != null) { 1491 synchronized (mSync) { 1492 final int N = mWaitingActivities.size(); 1493 for (int i=0; i<N; i++) { 1494 final ActivityWaiter aw = mWaitingActivities.get(i); 1495 final Intent intent = aw.intent; 1496 if (intent.filterEquals(activity.getIntent())) { 1497 aw.activity = activity; 1498 mMessageQueue.addIdleHandler(new ActivityGoing(aw)); 1499 } 1500 } 1501 } 1502 } 1503 } 1504 postPerformCreate(Activity activity)1505 private void postPerformCreate(Activity activity) { 1506 if (mActivityMonitors != null) { 1507 synchronized (mSync) { 1508 final int N = mActivityMonitors.size(); 1509 for (int i=0; i<N; i++) { 1510 final ActivityMonitor am = mActivityMonitors.get(i); 1511 am.match(activity, activity, activity.getIntent()); 1512 } 1513 } 1514 } 1515 } 1516 1517 /** 1518 * Perform calling of an activity's {@link Activity#onCreate} 1519 * method. The default implementation simply calls through to that method. 1520 * 1521 * @param activity The activity being created. 1522 * @param icicle The previously frozen state (or null) to pass through to onCreate(). 1523 */ callActivityOnCreate(Activity activity, Bundle icicle)1524 public void callActivityOnCreate(Activity activity, Bundle icicle) { 1525 prePerformCreate(activity); 1526 activity.performCreate(icicle); 1527 postPerformCreate(activity); 1528 } 1529 1530 /** 1531 * Perform calling of an activity's {@link Activity#onCreate} 1532 * method. The default implementation simply calls through to that method. 1533 * @param activity The activity being created. 1534 * @param icicle The previously frozen state (or null) to pass through to 1535 * @param persistentState The previously persisted state (or null) 1536 */ callActivityOnCreate(Activity activity, Bundle icicle, PersistableBundle persistentState)1537 public void callActivityOnCreate(Activity activity, Bundle icicle, 1538 PersistableBundle persistentState) { 1539 prePerformCreate(activity); 1540 activity.performCreate(icicle, persistentState); 1541 postPerformCreate(activity); 1542 } 1543 callActivityOnDestroy(Activity activity)1544 public void callActivityOnDestroy(Activity activity) { 1545 // TODO: the following block causes intermittent hangs when using startActivity 1546 // temporarily comment out until root cause is fixed (bug 2630683) 1547 // if (mWaitingActivities != null) { 1548 // synchronized (mSync) { 1549 // final int N = mWaitingActivities.size(); 1550 // for (int i=0; i<N; i++) { 1551 // final ActivityWaiter aw = mWaitingActivities.get(i); 1552 // final Intent intent = aw.intent; 1553 // if (intent.filterEquals(activity.getIntent())) { 1554 // aw.activity = activity; 1555 // mMessageQueue.addIdleHandler(new ActivityGoing(aw)); 1556 // } 1557 // } 1558 // } 1559 // } 1560 1561 activity.performDestroy(); 1562 } 1563 1564 /** 1565 * Perform calling of an activity's {@link Activity#onRestoreInstanceState} 1566 * method. The default implementation simply calls through to that method. 1567 * 1568 * @param activity The activity being restored. 1569 * @param savedInstanceState The previously saved state being restored. 1570 */ callActivityOnRestoreInstanceState(@onNull Activity activity, @NonNull Bundle savedInstanceState)1571 public void callActivityOnRestoreInstanceState(@NonNull Activity activity, 1572 @NonNull Bundle savedInstanceState) { 1573 activity.performRestoreInstanceState(savedInstanceState); 1574 } 1575 1576 /** 1577 * Perform calling of an activity's {@link Activity#onRestoreInstanceState} 1578 * method. The default implementation simply calls through to that method. 1579 * 1580 * @param activity The activity being restored. 1581 * @param savedInstanceState The previously saved state being restored (or null). 1582 * @param persistentState The previously persisted state (or null) 1583 */ callActivityOnRestoreInstanceState(@onNull Activity activity, @Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState)1584 public void callActivityOnRestoreInstanceState(@NonNull Activity activity, 1585 @Nullable Bundle savedInstanceState, 1586 @Nullable PersistableBundle persistentState) { 1587 activity.performRestoreInstanceState(savedInstanceState, persistentState); 1588 } 1589 1590 /** 1591 * Perform calling of an activity's {@link Activity#onPostCreate} method. 1592 * The default implementation simply calls through to that method. 1593 * 1594 * @param activity The activity being created. 1595 * @param savedInstanceState The previously saved state (or null) to pass through to 1596 * onPostCreate(). 1597 */ callActivityOnPostCreate(@onNull Activity activity, @Nullable Bundle savedInstanceState)1598 public void callActivityOnPostCreate(@NonNull Activity activity, 1599 @Nullable Bundle savedInstanceState) { 1600 activity.onPostCreate(savedInstanceState); 1601 } 1602 1603 /** 1604 * Perform calling of an activity's {@link Activity#onPostCreate} method. 1605 * The default implementation simply calls through to that method. 1606 * 1607 * @param activity The activity being created. 1608 * @param savedInstanceState The previously frozen state (or null) to pass through to 1609 * onPostCreate(). 1610 * @param persistentState The previously persisted state (or null) 1611 */ callActivityOnPostCreate(@onNull Activity activity, @Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState)1612 public void callActivityOnPostCreate(@NonNull Activity activity, 1613 @Nullable Bundle savedInstanceState, 1614 @Nullable PersistableBundle persistentState) { 1615 activity.onPostCreate(savedInstanceState, persistentState); 1616 } 1617 1618 /** 1619 * Perform calling of an activity's {@link Activity#onNewIntent} 1620 * method. The default implementation simply calls through to that method. 1621 * 1622 * @param activity The activity receiving a new Intent. 1623 * @param intent The new intent being received. 1624 */ callActivityOnNewIntent(Activity activity, Intent intent)1625 public void callActivityOnNewIntent(Activity activity, Intent intent) { 1626 if (android.security.Flags.contentUriPermissionApis()) { 1627 activity.performNewIntent(intent, new ComponentCaller(activity.getActivityToken(), 1628 /* callerToken */ null)); 1629 } else { 1630 activity.performNewIntent(intent); 1631 } 1632 } 1633 1634 /** 1635 * Same as {@link #callActivityOnNewIntent(Activity, Intent)}, but with an extra parameter for 1636 * the {@link ComponentCaller} instance associated with the app that sent the intent. 1637 * 1638 * @param activity The activity receiving a new Intent. 1639 * @param intent The new intent being received. 1640 * @param caller The {@link ComponentCaller} instance that launched the activity with the new 1641 * intent. 1642 */ 1643 @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS) callActivityOnNewIntent(@onNull Activity activity, @NonNull Intent intent, @NonNull ComponentCaller caller)1644 public void callActivityOnNewIntent(@NonNull Activity activity, @NonNull Intent intent, 1645 @NonNull ComponentCaller caller) { 1646 activity.performNewIntent(intent, caller); 1647 } 1648 1649 /** 1650 * @hide 1651 */ 1652 @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS) callActivityOnNewIntent(Activity activity, ReferrerIntent intent, @NonNull ComponentCaller caller)1653 public void callActivityOnNewIntent(Activity activity, ReferrerIntent intent, 1654 @NonNull ComponentCaller caller) { 1655 internalCallActivityOnNewIntent(activity, intent, caller); 1656 } 1657 1658 @FlaggedApi(android.security.Flags.FLAG_CONTENT_URI_PERMISSION_APIS) internalCallActivityOnNewIntent(Activity activity, ReferrerIntent intent, @NonNull ComponentCaller caller)1659 private void internalCallActivityOnNewIntent(Activity activity, ReferrerIntent intent, 1660 @NonNull ComponentCaller caller) { 1661 final String oldReferrer = activity.mReferrer; 1662 try { 1663 if (intent != null) { 1664 activity.mReferrer = intent.mReferrer; 1665 } 1666 Intent newIntent = intent != null ? new Intent(intent) : null; 1667 callActivityOnNewIntent(activity, newIntent, caller); 1668 } finally { 1669 activity.mReferrer = oldReferrer; 1670 } 1671 } 1672 1673 /** 1674 * @hide 1675 */ 1676 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) callActivityOnNewIntent(Activity activity, ReferrerIntent intent)1677 public void callActivityOnNewIntent(Activity activity, ReferrerIntent intent) { 1678 if (android.security.Flags.contentUriPermissionApis()) { 1679 internalCallActivityOnNewIntent(activity, intent, new ComponentCaller( 1680 activity.getActivityToken(), /* callerToken */ null)); 1681 } else { 1682 final String oldReferrer = activity.mReferrer; 1683 try { 1684 if (intent != null) { 1685 activity.mReferrer = intent.mReferrer; 1686 } 1687 callActivityOnNewIntent(activity, intent != null ? new Intent(intent) : null); 1688 } finally { 1689 activity.mReferrer = oldReferrer; 1690 } 1691 } 1692 } 1693 1694 /** 1695 * Perform calling of an activity's {@link Activity#onStart} 1696 * method. The default implementation simply calls through to that method. 1697 * 1698 * @param activity The activity being started. 1699 */ callActivityOnStart(Activity activity)1700 public void callActivityOnStart(Activity activity) { 1701 activity.onStart(); 1702 } 1703 1704 /** 1705 * Perform calling of an activity's {@link Activity#onRestart} 1706 * method. The default implementation simply calls through to that method. 1707 * 1708 * @param activity The activity being restarted. 1709 */ callActivityOnRestart(Activity activity)1710 public void callActivityOnRestart(Activity activity) { 1711 activity.onRestart(); 1712 } 1713 1714 /** 1715 * Perform calling of an activity's {@link Activity#onResume} method. The 1716 * default implementation simply calls through to that method. 1717 * 1718 * @param activity The activity being resumed. 1719 */ callActivityOnResume(Activity activity)1720 public void callActivityOnResume(Activity activity) { 1721 activity.mResumed = true; 1722 activity.onResume(); 1723 1724 if (mActivityMonitors != null) { 1725 synchronized (mSync) { 1726 final int N = mActivityMonitors.size(); 1727 for (int i=0; i<N; i++) { 1728 final ActivityMonitor am = mActivityMonitors.get(i); 1729 am.match(activity, activity, activity.getIntent()); 1730 } 1731 } 1732 } 1733 } 1734 1735 /** 1736 * Perform calling of an activity's {@link Activity#onStop} 1737 * method. The default implementation simply calls through to that method. 1738 * 1739 * @param activity The activity being stopped. 1740 */ callActivityOnStop(Activity activity)1741 public void callActivityOnStop(Activity activity) { 1742 activity.onStop(); 1743 } 1744 1745 /** 1746 * Perform calling of an activity's {@link Activity#onSaveInstanceState} 1747 * method. The default implementation simply calls through to that method. 1748 * 1749 * @param activity The activity being saved. 1750 * @param outState The bundle to pass to the call. 1751 */ callActivityOnSaveInstanceState(@onNull Activity activity, @NonNull Bundle outState)1752 public void callActivityOnSaveInstanceState(@NonNull Activity activity, 1753 @NonNull Bundle outState) { 1754 activity.performSaveInstanceState(outState); 1755 } 1756 1757 /** 1758 * Perform calling of an activity's {@link Activity#onSaveInstanceState} 1759 * method. The default implementation simply calls through to that method. 1760 * @param activity The activity being saved. 1761 * @param outState The bundle to pass to the call. 1762 * @param outPersistentState The persistent bundle to pass to the call. 1763 */ callActivityOnSaveInstanceState(@onNull Activity activity, @NonNull Bundle outState, @NonNull PersistableBundle outPersistentState)1764 public void callActivityOnSaveInstanceState(@NonNull Activity activity, 1765 @NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) { 1766 activity.performSaveInstanceState(outState, outPersistentState); 1767 } 1768 1769 /** 1770 * Perform calling of an activity's {@link Activity#onPause} method. The 1771 * default implementation simply calls through to that method. 1772 * 1773 * @param activity The activity being paused. 1774 */ callActivityOnPause(Activity activity)1775 public void callActivityOnPause(Activity activity) { 1776 activity.performPause(); 1777 } 1778 1779 /** 1780 * Perform calling of an activity's {@link Activity#onUserLeaveHint} method. 1781 * The default implementation simply calls through to that method. 1782 * 1783 * @param activity The activity being notified that the user has navigated away 1784 */ callActivityOnUserLeaving(Activity activity)1785 public void callActivityOnUserLeaving(Activity activity) { 1786 activity.performUserLeaving(); 1787 } 1788 1789 /** 1790 * Perform calling of an activity's {@link Activity#onPictureInPictureRequested} method. 1791 * The default implementation simply calls through to that method. 1792 * 1793 * @param activity The activity being notified that picture-in-picture is being requested. 1794 */ callActivityOnPictureInPictureRequested(@onNull Activity activity)1795 public void callActivityOnPictureInPictureRequested(@NonNull Activity activity) { 1796 activity.onPictureInPictureRequested(); 1797 } 1798 1799 /* 1800 * Starts allocation counting. This triggers a gc and resets the counts. 1801 * 1802 * @deprecated Accurate counting is a burden on the runtime and may be removed. 1803 */ 1804 @Deprecated startAllocCounting()1805 public void startAllocCounting() { 1806 // Before we start trigger a GC and reset the debug counts. Run the 1807 // finalizers and another GC before starting and stopping the alloc 1808 // counts. This will free up any objects that were just sitting around 1809 // waiting for their finalizers to be run. 1810 Runtime.getRuntime().gc(); 1811 Runtime.getRuntime().runFinalization(); 1812 Runtime.getRuntime().gc(); 1813 1814 Debug.resetAllCounts(); 1815 1816 // start the counts 1817 Debug.startAllocCounting(); 1818 } 1819 1820 /* 1821 * Stops allocation counting. 1822 * 1823 * @deprecated Accurate counting is a burden on the runtime and may be removed. 1824 */ 1825 @Deprecated stopAllocCounting()1826 public void stopAllocCounting() { 1827 Runtime.getRuntime().gc(); 1828 Runtime.getRuntime().runFinalization(); 1829 Runtime.getRuntime().gc(); 1830 Debug.stopAllocCounting(); 1831 } 1832 1833 /** 1834 * If Results already contains Key, it appends Value to the key's ArrayList 1835 * associated with the key. If the key doesn't already exist in results, it 1836 * adds the key/value pair to results. 1837 */ addValue(String key, int value, Bundle results)1838 private void addValue(String key, int value, Bundle results) { 1839 if (results.containsKey(key)) { 1840 List<Integer> list = results.getIntegerArrayList(key); 1841 if (list != null) { 1842 list.add(value); 1843 } 1844 } else { 1845 ArrayList<Integer> list = new ArrayList<Integer>(); 1846 list.add(value); 1847 results.putIntegerArrayList(key, list); 1848 } 1849 } 1850 1851 /** 1852 * Returns a bundle with the current results from the allocation counting. 1853 */ getAllocCounts()1854 public Bundle getAllocCounts() { 1855 Bundle results = new Bundle(); 1856 results.putLong("global_alloc_count", Debug.getGlobalAllocCount()); 1857 results.putLong("global_alloc_size", Debug.getGlobalAllocSize()); 1858 results.putLong("global_freed_count", Debug.getGlobalFreedCount()); 1859 results.putLong("global_freed_size", Debug.getGlobalFreedSize()); 1860 results.putLong("gc_invocation_count", Debug.getGlobalGcInvocationCount()); 1861 return results; 1862 } 1863 1864 /** 1865 * Returns a bundle with the counts for various binder counts for this process. Currently the only two that are 1866 * reported are the number of send and the number of received transactions. 1867 */ getBinderCounts()1868 public Bundle getBinderCounts() { 1869 Bundle results = new Bundle(); 1870 results.putLong("sent_transactions", Debug.getBinderSentTransactions()); 1871 results.putLong("received_transactions", Debug.getBinderReceivedTransactions()); 1872 return results; 1873 } 1874 1875 /** 1876 * Description of a Activity execution result to return to the original 1877 * activity. 1878 */ 1879 public static final class ActivityResult { 1880 /** 1881 * Create a new activity result. See {@link Activity#setResult} for 1882 * more information. 1883 * 1884 * @param resultCode The result code to propagate back to the 1885 * originating activity, often RESULT_CANCELED or RESULT_OK 1886 * @param resultData The data to propagate back to the originating 1887 * activity. 1888 */ ActivityResult(int resultCode, Intent resultData)1889 public ActivityResult(int resultCode, Intent resultData) { 1890 mResultCode = resultCode; 1891 mResultData = resultData; 1892 } 1893 1894 /** 1895 * Retrieve the result code contained in this result. 1896 */ getResultCode()1897 public int getResultCode() { 1898 return mResultCode; 1899 } 1900 1901 /** 1902 * Retrieve the data contained in this result. 1903 */ getResultData()1904 public Intent getResultData() { 1905 return mResultData; 1906 } 1907 1908 private final int mResultCode; 1909 private final Intent mResultData; 1910 } 1911 1912 /** 1913 * Execute a startActivity call made by the application. The default 1914 * implementation takes care of updating any active {@link ActivityMonitor} 1915 * objects and dispatches this call to the system activity manager; you can 1916 * override this to watch for the application to start an activity, and 1917 * modify what happens when it does. 1918 * 1919 * <p>This method returns an {@link ActivityResult} object, which you can 1920 * use when intercepting application calls to avoid performing the start 1921 * activity action but still return the result the application is 1922 * expecting. To do this, override this method to catch the call to start 1923 * activity so that it returns a new ActivityResult containing the results 1924 * you would like the application to see, and don't call up to the super 1925 * class. Note that an application is only expecting a result if 1926 * <var>requestCode</var> is >= 0. 1927 * 1928 * <p>This method throws {@link android.content.ActivityNotFoundException} 1929 * if there was no Activity found to run the given Intent. 1930 * 1931 * @param who The Context from which the activity is being started. 1932 * @param contextThread The main thread of the Context from which the activity 1933 * is being started. 1934 * @param token Internal token identifying to the system who is starting 1935 * the activity; may be null. 1936 * @param target Which activity is performing the start (and thus receiving 1937 * any result); may be null if this call is not being made 1938 * from an activity. 1939 * @param intent The actual Intent to start. 1940 * @param requestCode Identifier for this request's result; less than zero 1941 * if the caller is not expecting a result. 1942 * @param options Addition options. 1943 * 1944 * @return To force the return of a particular result, return an 1945 * ActivityResult object containing the desired data; otherwise 1946 * return null. The default implementation always returns null. 1947 * 1948 * @throws android.content.ActivityNotFoundException 1949 * 1950 * @see Activity#startActivity(Intent) 1951 * @see Activity#startActivityForResult(Intent, int) 1952 * 1953 * {@hide} 1954 */ 1955 @UnsupportedAppUsage execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options)1956 public ActivityResult execStartActivity( 1957 Context who, IBinder contextThread, IBinder token, Activity target, 1958 Intent intent, int requestCode, Bundle options) { 1959 if (DEBUG_START_ACTIVITY) { 1960 Log.d(TAG, "startActivity: who=" + who + " source=" + target + " intent=" + intent 1961 + " requestCode=" + requestCode + " options=" + options, new Throwable()); 1962 } 1963 Objects.requireNonNull(intent); 1964 IApplicationThread whoThread = (IApplicationThread) contextThread; 1965 Uri referrer = target != null ? target.onProvideReferrer() : null; 1966 if (referrer != null) { 1967 intent.putExtra(Intent.EXTRA_REFERRER, referrer); 1968 } 1969 if (isSdkSandboxAllowedToStartActivities()) { 1970 adjustIntentForCtsInSdkSandboxInstrumentation(intent); 1971 } 1972 if (mActivityMonitors != null) { 1973 synchronized (mSync) { 1974 final int N = mActivityMonitors.size(); 1975 for (int i=0; i<N; i++) { 1976 final ActivityMonitor am = mActivityMonitors.get(i); 1977 ActivityResult result = null; 1978 if (am.ignoreMatchingSpecificIntents()) { 1979 if (options == null) { 1980 options = ActivityOptions.makeBasic().toBundle(); 1981 } 1982 result = am.onStartActivity(who, intent, options); 1983 } 1984 if (result != null) { 1985 am.mHits++; 1986 return result; 1987 } else if (am.match(who, null, intent)) { 1988 am.mHits++; 1989 if (am.isBlocking()) { 1990 return requestCode >= 0 ? am.getResult() : null; 1991 } 1992 break; 1993 } 1994 } 1995 } 1996 } 1997 try { 1998 intent.migrateExtraStreamToClipData(who); 1999 intent.prepareToLeaveProcess(who); 2000 int result = ActivityTaskManager.getService().startActivity(whoThread, 2001 who.getOpPackageName(), who.getAttributionTag(), intent, 2002 intent.resolveTypeIfNeeded(who.getContentResolver()), token, 2003 target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); 2004 notifyStartActivityResult(result, options); 2005 checkStartActivityResult(result, intent); 2006 } catch (RemoteException e) { 2007 throw new RuntimeException("Failure from system", e); 2008 } 2009 return null; 2010 } 2011 2012 /** 2013 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, 2014 * but accepts an array of activities to be started. Note that active 2015 * {@link ActivityMonitor} objects only match against the first activity in 2016 * the array. 2017 * 2018 * {@hide} 2019 */ 2020 @UnsupportedAppUsage execStartActivities(Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options)2021 public void execStartActivities(Context who, IBinder contextThread, 2022 IBinder token, Activity target, Intent[] intents, Bundle options) { 2023 execStartActivitiesAsUser(who, contextThread, token, target, intents, options, 2024 who.getUserId()); 2025 } 2026 2027 /** 2028 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, 2029 * but accepts an array of activities to be started. Note that active 2030 * {@link ActivityMonitor} objects only match against the first activity in 2031 * the array. 2032 * 2033 * @return The corresponding flag {@link ActivityManager#START_CANCELED}, 2034 * {@link ActivityManager#START_SUCCESS} etc. indicating whether the launch was 2035 * successful. 2036 * 2037 * {@hide} 2038 */ 2039 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) execStartActivitiesAsUser(Context who, IBinder contextThread, IBinder token, Activity target, Intent[] intents, Bundle options, int userId)2040 public int execStartActivitiesAsUser(Context who, IBinder contextThread, 2041 IBinder token, Activity target, Intent[] intents, Bundle options, 2042 int userId) { 2043 if (DEBUG_START_ACTIVITY) { 2044 StringJoiner joiner = new StringJoiner(", "); 2045 for (Intent i : intents) { 2046 joiner.add(i.toString()); 2047 } 2048 Log.d(TAG, "startActivities: who=" + who + " source=" + target + " userId=" + userId 2049 + " intents=[" + joiner + "] options=" + options, new Throwable()); 2050 } 2051 Objects.requireNonNull(intents); 2052 for (int i = intents.length - 1; i >= 0; i--) { 2053 Objects.requireNonNull(intents[i]); 2054 } 2055 IApplicationThread whoThread = (IApplicationThread) contextThread; 2056 if (isSdkSandboxAllowedToStartActivities()) { 2057 for (Intent intent : intents) { 2058 adjustIntentForCtsInSdkSandboxInstrumentation(intent); 2059 } 2060 } 2061 if (mActivityMonitors != null) { 2062 synchronized (mSync) { 2063 final int N = mActivityMonitors.size(); 2064 for (int i=0; i<N; i++) { 2065 final ActivityMonitor am = mActivityMonitors.get(i); 2066 ActivityResult result = null; 2067 if (am.ignoreMatchingSpecificIntents()) { 2068 if (options == null) { 2069 options = ActivityOptions.makeBasic().toBundle(); 2070 } 2071 result = am.onStartActivity(who, intents[0], options); 2072 } 2073 if (result != null) { 2074 am.mHits++; 2075 return ActivityManager.START_CANCELED; 2076 } else if (am.match(who, null, intents[0])) { 2077 am.mHits++; 2078 if (am.isBlocking()) { 2079 return ActivityManager.START_CANCELED; 2080 } 2081 break; 2082 } 2083 } 2084 } 2085 } 2086 try { 2087 String[] resolvedTypes = new String[intents.length]; 2088 for (int i=0; i<intents.length; i++) { 2089 intents[i].migrateExtraStreamToClipData(who); 2090 intents[i].prepareToLeaveProcess(who); 2091 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver()); 2092 } 2093 int result = ActivityTaskManager.getService().startActivities(whoThread, 2094 who.getOpPackageName(), who.getAttributionTag(), intents, resolvedTypes, 2095 token, options, userId); 2096 notifyStartActivityResult(result, options); 2097 checkStartActivityResult(result, intents[0]); 2098 return result; 2099 } catch (RemoteException e) { 2100 throw new RuntimeException("Failure from system", e); 2101 } 2102 } 2103 2104 /** 2105 * Like {@link #execStartActivity(android.content.Context, android.os.IBinder, 2106 * android.os.IBinder, String, android.content.Intent, int, android.os.Bundle)}, 2107 * but for calls from a {@link Fragment}. 2108 * 2109 * @param who The Context from which the activity is being started. 2110 * @param contextThread The main thread of the Context from which the activity 2111 * is being started. 2112 * @param token Internal token identifying to the system who is starting 2113 * the activity; may be null. 2114 * @param target Which element is performing the start (and thus receiving 2115 * any result). 2116 * @param intent The actual Intent to start. 2117 * @param requestCode Identifier for this request's result; less than zero 2118 * if the caller is not expecting a result. 2119 * 2120 * @return To force the return of a particular result, return an 2121 * ActivityResult object containing the desired data; otherwise 2122 * return null. The default implementation always returns null. 2123 * 2124 * @throws android.content.ActivityNotFoundException 2125 * 2126 * @see Activity#startActivity(Intent) 2127 * @see Activity#startActivityForResult(Intent, int) 2128 * 2129 * {@hide} 2130 */ 2131 @UnsupportedAppUsage execStartActivity( Context who, IBinder contextThread, IBinder token, String target, Intent intent, int requestCode, Bundle options)2132 public ActivityResult execStartActivity( 2133 Context who, IBinder contextThread, IBinder token, String target, 2134 Intent intent, int requestCode, Bundle options) { 2135 if (DEBUG_START_ACTIVITY) { 2136 Log.d(TAG, "startActivity: who=" + who + " target=" + target 2137 + " intent=" + intent + " requestCode=" + requestCode 2138 + " options=" + options, new Throwable()); 2139 } 2140 Objects.requireNonNull(intent); 2141 IApplicationThread whoThread = (IApplicationThread) contextThread; 2142 if (isSdkSandboxAllowedToStartActivities()) { 2143 adjustIntentForCtsInSdkSandboxInstrumentation(intent); 2144 } 2145 if (mActivityMonitors != null) { 2146 synchronized (mSync) { 2147 final int N = mActivityMonitors.size(); 2148 for (int i=0; i<N; i++) { 2149 final ActivityMonitor am = mActivityMonitors.get(i); 2150 ActivityResult result = null; 2151 if (am.ignoreMatchingSpecificIntents()) { 2152 if (options == null) { 2153 options = ActivityOptions.makeBasic().toBundle(); 2154 } 2155 result = am.onStartActivity(who, intent, options); 2156 } 2157 if (result != null) { 2158 am.mHits++; 2159 return result; 2160 } else if (am.match(who, null, intent)) { 2161 am.mHits++; 2162 if (am.isBlocking()) { 2163 return requestCode >= 0 ? am.getResult() : null; 2164 } 2165 break; 2166 } 2167 } 2168 } 2169 } 2170 try { 2171 intent.migrateExtraStreamToClipData(who); 2172 intent.prepareToLeaveProcess(who); 2173 int result = ActivityTaskManager.getService().startActivity(whoThread, 2174 who.getOpPackageName(), who.getAttributionTag(), intent, 2175 intent.resolveTypeIfNeeded(who.getContentResolver()), token, target, 2176 requestCode, 0, null, options); 2177 notifyStartActivityResult(result, options); 2178 checkStartActivityResult(result, intent); 2179 } catch (RemoteException e) { 2180 throw new RuntimeException("Failure from system", e); 2181 } 2182 return null; 2183 } 2184 2185 /** 2186 * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, 2187 * but for starting as a particular user. 2188 * 2189 * @param who The Context from which the activity is being started. 2190 * @param contextThread The main thread of the Context from which the activity 2191 * is being started. 2192 * @param token Internal token identifying to the system who is starting 2193 * the activity; may be null. 2194 * @param target Which fragment is performing the start (and thus receiving 2195 * any result). 2196 * @param intent The actual Intent to start. 2197 * @param requestCode Identifier for this request's result; less than zero 2198 * if the caller is not expecting a result. 2199 * 2200 * @return To force the return of a particular result, return an 2201 * ActivityResult object containing the desired data; otherwise 2202 * return null. The default implementation always returns null. 2203 * 2204 * @throws android.content.ActivityNotFoundException 2205 * 2206 * @see Activity#startActivity(Intent) 2207 * @see Activity#startActivityForResult(Intent, int) 2208 * 2209 * {@hide} 2210 */ 2211 @UnsupportedAppUsage execStartActivity( Context who, IBinder contextThread, IBinder token, String resultWho, Intent intent, int requestCode, Bundle options, UserHandle user)2212 public ActivityResult execStartActivity( 2213 Context who, IBinder contextThread, IBinder token, String resultWho, 2214 Intent intent, int requestCode, Bundle options, UserHandle user) { 2215 if (DEBUG_START_ACTIVITY) { 2216 Log.d(TAG, "startActivity: who=" + who + " user=" + user + " intent=" + intent 2217 + " requestCode=" + requestCode + " resultWho=" + resultWho 2218 + " options=" + options, new Throwable()); 2219 } 2220 Objects.requireNonNull(intent); 2221 IApplicationThread whoThread = (IApplicationThread) contextThread; 2222 if (isSdkSandboxAllowedToStartActivities()) { 2223 adjustIntentForCtsInSdkSandboxInstrumentation(intent); 2224 } 2225 if (mActivityMonitors != null) { 2226 synchronized (mSync) { 2227 final int N = mActivityMonitors.size(); 2228 for (int i=0; i<N; i++) { 2229 final ActivityMonitor am = mActivityMonitors.get(i); 2230 ActivityResult result = null; 2231 if (am.ignoreMatchingSpecificIntents()) { 2232 if (options == null) { 2233 options = ActivityOptions.makeBasic().toBundle(); 2234 } 2235 result = am.onStartActivity(who, intent, options); 2236 } 2237 if (result != null) { 2238 am.mHits++; 2239 return result; 2240 } else if (am.match(who, null, intent)) { 2241 am.mHits++; 2242 if (am.isBlocking()) { 2243 return requestCode >= 0 ? am.getResult() : null; 2244 } 2245 break; 2246 } 2247 } 2248 } 2249 } 2250 try { 2251 intent.migrateExtraStreamToClipData(who); 2252 intent.prepareToLeaveProcess(who); 2253 int result = ActivityTaskManager.getService().startActivityAsUser(whoThread, 2254 who.getOpPackageName(), who.getAttributionTag(), intent, 2255 intent.resolveTypeIfNeeded(who.getContentResolver()), token, resultWho, 2256 requestCode, 0, null, options, user.getIdentifier()); 2257 notifyStartActivityResult(result, options); 2258 checkStartActivityResult(result, intent); 2259 } catch (RemoteException e) { 2260 throw new RuntimeException("Failure from system", e); 2261 } 2262 return null; 2263 } 2264 2265 /** 2266 * Special version! 2267 * @hide 2268 */ 2269 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) execStartActivityAsCaller( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options, boolean ignoreTargetSecurity, int userId)2270 public ActivityResult execStartActivityAsCaller( 2271 Context who, IBinder contextThread, IBinder token, Activity target, 2272 Intent intent, int requestCode, Bundle options, 2273 boolean ignoreTargetSecurity, int userId) { 2274 if (DEBUG_START_ACTIVITY) { 2275 Log.d(TAG, "startActivity: who=" + who + " source=" + target + " userId=" + userId 2276 + " intent=" + intent + " requestCode=" + requestCode 2277 + " ignoreTargetSecurity=" + ignoreTargetSecurity + " options=" + options, 2278 new Throwable()); 2279 } 2280 Objects.requireNonNull(intent); 2281 IApplicationThread whoThread = (IApplicationThread) contextThread; 2282 if (isSdkSandboxAllowedToStartActivities()) { 2283 adjustIntentForCtsInSdkSandboxInstrumentation(intent); 2284 } 2285 if (mActivityMonitors != null) { 2286 synchronized (mSync) { 2287 final int N = mActivityMonitors.size(); 2288 for (int i=0; i<N; i++) { 2289 final ActivityMonitor am = mActivityMonitors.get(i); 2290 ActivityResult result = null; 2291 if (am.ignoreMatchingSpecificIntents()) { 2292 if (options == null) { 2293 options = ActivityOptions.makeBasic().toBundle(); 2294 } 2295 result = am.onStartActivity(who, intent, options); 2296 } 2297 if (result != null) { 2298 am.mHits++; 2299 return result; 2300 } else if (am.match(who, null, intent)) { 2301 am.mHits++; 2302 if (am.isBlocking()) { 2303 return requestCode >= 0 ? am.getResult() : null; 2304 } 2305 break; 2306 } 2307 } 2308 } 2309 } 2310 try { 2311 intent.migrateExtraStreamToClipData(who); 2312 intent.prepareToLeaveProcess(who); 2313 int result = ActivityTaskManager.getService() 2314 .startActivityAsCaller(whoThread, who.getOpPackageName(), intent, 2315 intent.resolveTypeIfNeeded(who.getContentResolver()), 2316 token, target != null ? target.mEmbeddedID : null, 2317 requestCode, 0, null, options, 2318 ignoreTargetSecurity, userId); 2319 notifyStartActivityResult(result, options); 2320 checkStartActivityResult(result, intent); 2321 } catch (RemoteException e) { 2322 throw new RuntimeException("Failure from system", e); 2323 } 2324 return null; 2325 } 2326 2327 /** 2328 * Special version! 2329 * @hide 2330 */ 2331 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) execStartActivityFromAppTask( Context who, IBinder contextThread, IAppTask appTask, Intent intent, Bundle options)2332 public void execStartActivityFromAppTask( 2333 Context who, IBinder contextThread, IAppTask appTask, 2334 Intent intent, Bundle options) { 2335 if (DEBUG_START_ACTIVITY) { 2336 Log.d(TAG, "startActivity: who=" + who + " intent=" + intent 2337 + " options=" + options, new Throwable()); 2338 } 2339 Objects.requireNonNull(intent); 2340 IApplicationThread whoThread = (IApplicationThread) contextThread; 2341 if (isSdkSandboxAllowedToStartActivities()) { 2342 adjustIntentForCtsInSdkSandboxInstrumentation(intent); 2343 } 2344 if (mActivityMonitors != null) { 2345 synchronized (mSync) { 2346 final int N = mActivityMonitors.size(); 2347 for (int i=0; i<N; i++) { 2348 final ActivityMonitor am = mActivityMonitors.get(i); 2349 ActivityResult result = null; 2350 if (am.ignoreMatchingSpecificIntents()) { 2351 if (options == null) { 2352 options = ActivityOptions.makeBasic().toBundle(); 2353 } 2354 result = am.onStartActivity(who, intent, options); 2355 } 2356 if (result != null) { 2357 am.mHits++; 2358 return; 2359 } else if (am.match(who, null, intent)) { 2360 am.mHits++; 2361 if (am.isBlocking()) { 2362 return; 2363 } 2364 break; 2365 } 2366 } 2367 } 2368 } 2369 try { 2370 intent.migrateExtraStreamToClipData(who); 2371 intent.prepareToLeaveProcess(who); 2372 int result = appTask.startActivity(whoThread.asBinder(), who.getOpPackageName(), 2373 who.getAttributionTag(), intent, 2374 intent.resolveTypeIfNeeded(who.getContentResolver()), options); 2375 notifyStartActivityResult(result, options); 2376 checkStartActivityResult(result, intent); 2377 } catch (RemoteException e) { 2378 throw new RuntimeException("Failure from system", e); 2379 } 2380 return; 2381 } 2382 init(ActivityThread thread, Context instrContext, Context appContext, ComponentName component, IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection)2383 /*package*/ final void init(ActivityThread thread, 2384 Context instrContext, Context appContext, ComponentName component, 2385 IInstrumentationWatcher watcher, IUiAutomationConnection uiAutomationConnection) { 2386 mThread = thread; 2387 mMessageQueue = mThread.getLooper().myQueue(); 2388 mInstrContext = instrContext; 2389 mAppContext = appContext; 2390 mComponent = component; 2391 mWatcher = watcher; 2392 mUiAutomationConnection = uiAutomationConnection; 2393 } 2394 2395 /** 2396 * Only sets the ActivityThread up, keeps everything else null because app is not being 2397 * instrumented. 2398 */ basicInit(ActivityThread thread)2399 final void basicInit(ActivityThread thread) { 2400 mThread = thread; 2401 } 2402 2403 /** 2404 * Only sets the Context up, keeps everything else null. 2405 * 2406 * @hide 2407 */ 2408 @android.ravenwood.annotation.RavenwoodKeep basicInit(Context context)2409 public final void basicInit(Context context) { 2410 mInstrContext = context; 2411 mAppContext = context; 2412 } 2413 2414 /** @hide */ 2415 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) checkStartActivityResult(int res, Object intent)2416 public static void checkStartActivityResult(int res, Object intent) { 2417 if (!ActivityManager.isStartResultFatalError(res)) { 2418 return; 2419 } 2420 2421 switch (res) { 2422 case ActivityManager.START_INTENT_NOT_RESOLVED: 2423 case ActivityManager.START_CLASS_NOT_FOUND: 2424 if (intent instanceof Intent && ((Intent)intent).getComponent() != null) 2425 throw new ActivityNotFoundException( 2426 "Unable to find explicit activity class " 2427 + ((Intent)intent).getComponent().toShortString() 2428 + "; have you declared this activity in your AndroidManifest.xml" 2429 + ", or does your intent not match its declared <intent-filter>?"); 2430 throw new ActivityNotFoundException( 2431 "No Activity found to handle " + intent); 2432 case ActivityManager.START_PERMISSION_DENIED: 2433 throw new SecurityException("Not allowed to start activity " 2434 + intent); 2435 case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 2436 throw new AndroidRuntimeException( 2437 "FORWARD_RESULT_FLAG used while also requesting a result"); 2438 case ActivityManager.START_NOT_ACTIVITY: 2439 throw new IllegalArgumentException( 2440 "PendingIntent is not an activity"); 2441 case ActivityManager.START_NOT_VOICE_COMPATIBLE: 2442 throw new SecurityException( 2443 "Starting under voice control not allowed for: " + intent); 2444 case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION: 2445 throw new IllegalStateException( 2446 "Session calling startVoiceActivity does not match active session"); 2447 case ActivityManager.START_VOICE_HIDDEN_SESSION: 2448 throw new IllegalStateException( 2449 "Cannot start voice activity on a hidden session"); 2450 case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION: 2451 throw new IllegalStateException( 2452 "Session calling startAssistantActivity does not match active session"); 2453 case ActivityManager.START_ASSISTANT_HIDDEN_SESSION: 2454 throw new IllegalStateException( 2455 "Cannot start assistant activity on a hidden session"); 2456 case ActivityManager.START_CANCELED: 2457 throw new AndroidRuntimeException("Activity could not be started for " 2458 + intent); 2459 default: 2460 throw new AndroidRuntimeException("Unknown error code " 2461 + res + " when starting " + intent); 2462 } 2463 } 2464 validateNotAppThread()2465 private final void validateNotAppThread() { 2466 if (Looper.myLooper() == Looper.getMainLooper()) { 2467 throw new RuntimeException( 2468 "This method can not be called from the main application thread"); 2469 } 2470 } 2471 2472 /** 2473 * Gets the {@link UiAutomation} instance with no flags set. 2474 * <p> 2475 * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation} 2476 * work across application boundaries while the APIs exposed by the instrumentation 2477 * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will 2478 * not allow you to inject the event in an app different from the instrumentation 2479 * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)} 2480 * will work regardless of the current application. 2481 * </p> 2482 * <p> 2483 * A typical test case should be using either the {@link UiAutomation} or 2484 * {@link Instrumentation} APIs. Using both APIs at the same time is not 2485 * a mistake by itself but a client has to be aware of the APIs limitations. 2486 * </p> 2487 * <p> 2488 * Equivalent to {@code getUiAutomation(0)}. If a {@link UiAutomation} exists with different 2489 * flags, the flags on that instance will be changed, and then it will be returned. 2490 * </p> 2491 * <p> 2492 * Compatibility mode: This method is infallible for apps targeted for 2493 * {@link Build.VERSION_CODES#R} and earlier versions; for apps targeted for later versions, it 2494 * will return null if {@link UiAutomation} fails to connect. The caller can check the return 2495 * value and retry on error. 2496 * </p> 2497 * 2498 * @return The UI automation instance. 2499 * 2500 * @see UiAutomation 2501 */ getUiAutomation()2502 public UiAutomation getUiAutomation() { 2503 return getUiAutomation(0); 2504 } 2505 2506 /** 2507 * Gets the {@link UiAutomation} instance with flags set. 2508 * <p> 2509 * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation} 2510 * work across application boundaries while the APIs exposed by the instrumentation 2511 * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will 2512 * not allow you to inject the event in an app different from the instrumentation 2513 * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)} 2514 * will work regardless of the current application. 2515 * </p> 2516 * <p> 2517 * A typical test case should be using either the {@link UiAutomation} or 2518 * {@link Instrumentation} APIs. Using both APIs at the same time is not 2519 * a mistake by itself but a client has to be aware of the APIs limitations. 2520 * </p> 2521 * <p> 2522 * If a {@link UiAutomation} exists with different flags, the flags on that instance will be 2523 * changed, and then it will be returned. 2524 * </p> 2525 * <p> 2526 * Compatibility mode: This method is infallible for apps targeted for 2527 * {@link Build.VERSION_CODES#R} and earlier versions; for apps targeted for later versions, it 2528 * will return null if {@link UiAutomation} fails to connect. The caller can check the return 2529 * value and retry on error. 2530 * </p> 2531 * 2532 * @param flags The flags to be passed to the UiAutomation, for example 2533 * {@link UiAutomation#FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES}, 2534 * {@link UiAutomation#FLAG_DONT_USE_ACCESSIBILITY}. 2535 * 2536 * @return The UI automation instance. 2537 * 2538 * @see UiAutomation 2539 */ getUiAutomation(@iAutomationFlags int flags)2540 public UiAutomation getUiAutomation(@UiAutomationFlags int flags) { 2541 boolean mustCreateNewAutomation = (mUiAutomation == null) || (mUiAutomation.isDestroyed()); 2542 2543 if (mUiAutomationConnection != null) { 2544 if (!mustCreateNewAutomation && (mUiAutomation.getFlags() == flags)) { 2545 return mUiAutomation; 2546 } 2547 if (mustCreateNewAutomation) { 2548 mUiAutomation = new UiAutomation(getTargetContext(), mUiAutomationConnection); 2549 } else { 2550 mUiAutomation.disconnect(); 2551 } 2552 if (getTargetContext().getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R) { 2553 mUiAutomation.connect(flags); 2554 return mUiAutomation; 2555 } 2556 final long startUptime = SystemClock.uptimeMillis(); 2557 try { 2558 mUiAutomation.connectWithTimeout(flags, CONNECT_TIMEOUT_MILLIS); 2559 return mUiAutomation; 2560 } catch (TimeoutException e) { 2561 final long waited = SystemClock.uptimeMillis() - startUptime; 2562 Log.e(TAG, "Unable to connect to UiAutomation. Waited for " + waited + " ms", e); 2563 mUiAutomation.destroy(); 2564 mUiAutomation = null; 2565 } 2566 } 2567 return null; 2568 } 2569 2570 /** 2571 * Takes control of the execution of messages on the specified looper until 2572 * {@link TestLooperManager#release} is called. 2573 */ 2574 @android.ravenwood.annotation.RavenwoodKeep acquireLooperManager(Looper looper)2575 public TestLooperManager acquireLooperManager(Looper looper) { 2576 checkInstrumenting("acquireLooperManager"); 2577 return new TestLooperManager(looper); 2578 } 2579 2580 private final class InstrumentationThread extends Thread { InstrumentationThread(String name)2581 public InstrumentationThread(String name) { 2582 super(name); 2583 } run()2584 public void run() { 2585 try { 2586 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 2587 } catch (RuntimeException e) { 2588 Log.w(TAG, "Exception setting priority of instrumentation thread " 2589 + Process.myTid(), e); 2590 } 2591 if (mAutomaticPerformanceSnapshots) { 2592 startPerformanceSnapshot(); 2593 } 2594 onStart(); 2595 } 2596 } 2597 2598 private static final class EmptyRunnable implements Runnable { run()2599 public void run() { 2600 } 2601 } 2602 2603 private static final class SyncRunnable implements Runnable { 2604 private final Runnable mTarget; 2605 private boolean mComplete; 2606 SyncRunnable(Runnable target)2607 public SyncRunnable(Runnable target) { 2608 mTarget = target; 2609 } 2610 run()2611 public void run() { 2612 mTarget.run(); 2613 synchronized (this) { 2614 mComplete = true; 2615 notifyAll(); 2616 } 2617 } 2618 waitForComplete()2619 public void waitForComplete() { 2620 synchronized (this) { 2621 while (!mComplete) { 2622 try { 2623 wait(); 2624 } catch (InterruptedException e) { 2625 } 2626 } 2627 } 2628 } 2629 } 2630 2631 private static final class ActivityWaiter { 2632 public final Intent intent; 2633 public Activity activity; 2634 ActivityWaiter(Intent _intent)2635 public ActivityWaiter(Intent _intent) { 2636 intent = _intent; 2637 } 2638 } 2639 2640 private final class ActivityGoing implements MessageQueue.IdleHandler { 2641 private final ActivityWaiter mWaiter; 2642 ActivityGoing(ActivityWaiter waiter)2643 public ActivityGoing(ActivityWaiter waiter) { 2644 mWaiter = waiter; 2645 } 2646 queueIdle()2647 public final boolean queueIdle() { 2648 synchronized (mSync) { 2649 mWaitingActivities.remove(mWaiter); 2650 mSync.notifyAll(); 2651 } 2652 return false; 2653 } 2654 } 2655 2656 private static final class Idler implements MessageQueue.IdleHandler { 2657 private final Runnable mCallback; 2658 private boolean mIdle; 2659 Idler(Runnable callback)2660 public Idler(Runnable callback) { 2661 mCallback = callback; 2662 mIdle = false; 2663 } 2664 queueIdle()2665 public final boolean queueIdle() { 2666 if (mCallback != null) { 2667 mCallback.run(); 2668 } 2669 synchronized (this) { 2670 mIdle = true; 2671 notifyAll(); 2672 } 2673 return false; 2674 } 2675 waitForIdle()2676 public void waitForIdle() { 2677 synchronized (this) { 2678 while (!mIdle) { 2679 try { 2680 wait(); 2681 } catch (InterruptedException e) { 2682 } 2683 } 2684 } 2685 } 2686 } 2687 } 2688