1 /* 2 * Copyright (C) 2008 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.cts; 18 19 import android.app.Activity; 20 import android.content.BroadcastReceiver; 21 import android.content.ComponentName; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.os.Binder; 26 import android.os.Bundle; 27 import android.os.Handler; 28 import android.os.IBinder; 29 import android.os.Message; 30 import android.os.Parcel; 31 import android.os.Parcelable; 32 import android.test.PerformanceTestCase; 33 import android.util.Log; 34 35 import java.util.ArrayList; 36 import java.util.HashMap; 37 import java.util.List; 38 import java.util.Map; 39 40 class MyBadParcelable implements Parcelable { 41 public MyBadParcelable() { 42 } 43 44 public void writeToParcel(Parcel out, int flags) { 45 out.writeString("I am bad"); 46 } 47 48 public int describeContents() { 49 return 0; 50 } 51 52 public static final Parcelable.Creator<MyBadParcelable> CREATOR = 53 new Parcelable.Creator<MyBadParcelable>() { 54 public MyBadParcelable createFromParcel(Parcel in) { 55 return new MyBadParcelable(in); 56 } 57 58 public MyBadParcelable[] newArray(int size) { 59 return new MyBadParcelable[size]; 60 } 61 }; 62 63 public MyBadParcelable(Parcel in) { 64 in.readString(); 65 } 66 } 67 68 public class LaunchpadActivity extends Activity { 69 public interface CallingTest extends PerformanceTestCase.Intermediates { 70 public void startTiming(boolean realTime); 71 72 public void addIntermediate(String name); 73 74 public void addIntermediate(String name, long timeInNS); 75 76 public void finishTiming(boolean realTime); 77 78 public void activityFinished(int resultCode, Intent data, RuntimeException where); 79 } 80 81 // Also used as the Binder interface descriptor string in these tests 82 public static final String LAUNCH = "android.app.cts.activity.LAUNCH"; 83 84 public static final String FORWARD_RESULT = "android.app.cts.activity.FORWARD_RESULT"; 85 public static final String RETURNED_RESULT = "android.app.cts.activity.RETURNED_RESULT"; 86 87 public static final String BAD_PARCELABLE = "android.app.cts.activity.BAD_PARCELABLE"; 88 89 public static final int LAUNCHED_RESULT = 1; 90 public static final int FORWARDED_RESULT = 2; 91 92 public static final String LIFECYCLE_BASIC = "android.app.cts.activity.LIFECYCLE_BASIC"; 93 public static final String LIFECYCLE_SCREEN = "android.app.cts.activity.LIFECYCLE_SCREEN"; 94 public static final String LIFECYCLE_DIALOG = "android.app.cts.activity.LIFECYCLE_DIALOG"; 95 96 public static final String BROADCAST_REGISTERED = "android.app.cts.activity.BROADCAST_REGISTERED"; 97 public static final String BROADCAST_LOCAL = "android.app.cts.activity.BROADCAST_LOCAL"; 98 public static final String BROADCAST_REMOTE = "android.app.cts.activity.BROADCAST_REMOTE"; 99 public static final String BROADCAST_ALL = "android.app.cts.activity.BROADCAST_ALL"; 100 public static final String BROADCAST_REPEAT = "android.app.cts.activity.BROADCAST_REPEAT"; 101 public static final String BROADCAST_MULTI = "android.app.cts.activity.BROADCAST_MULTI"; 102 public static final String BROADCAST_ABORT = "android.app.cts.activity.BROADCAST_ABORT"; 103 104 public static final String EXPANDLIST_SELECT = "EXPANDLIST_SELECT"; 105 public static final String EXPANDLIST_VIEW = "EXPANDLIST_VIEW"; 106 public static final String EXPANDLIST_CALLBACK = "EXPANDLIST_CALLBACK"; 107 108 public static final String BROADCAST_STICKY1 = "android.app.cts.activity.BROADCAST_STICKY1"; 109 public static final String BROADCAST_STICKY2 = "android.app.cts.activity.BROADCAST_STICKY2"; 110 111 public static final String ALIAS_ACTIVITY = "android.app.cts.activity.ALIAS_ACTIVITY"; 112 113 public static final String RECEIVER_REG = "receiver-reg"; 114 public static final String RECEIVER_LOCAL = "receiver-local"; 115 public static final String RECEIVER_REMOTE = "receiver-remote"; 116 public static final String RECEIVER_ABORT = "receiver-abort"; 117 118 public static final String DATA_1 = "one"; 119 public static final String DATA_2 = "two"; 120 121 public static final String ON_START = "onStart"; 122 public static final String ON_RESTART = "onRestart"; 123 public static final String ON_RESUME = "onResume"; 124 public static final String ON_FREEZE = "onSaveInstanceState"; 125 public static final String ON_PAUSE = "onPause"; 126 127 // ON_STOP and ON_DESTROY are not tested because they may not be called. 128 129 public static final String DO_FINISH = "finish"; 130 public static final String DO_LOCAL_SCREEN = "local-screen"; 131 public static final String DO_LOCAL_DIALOG = "local-dialog"; 132 133 private static final String TAG = "LaunchpadActivity"; 134 135 private boolean mBadParcelable = false; 136 137 private boolean mStarted = false; 138 139 private int mResultCode = RESULT_CANCELED; 140 private Intent mData = new Intent().setAction("No result received"); 141 private RuntimeException mResultStack = null; 142 143 /** Index into the {@link #mNextLifecycle} array. */ 144 private int mNextLifecycle; 145 146 /** Current lifecycle expected to be followed. */ 147 private String[] mExpectedLifecycle; 148 149 /** Other possible lifecycles. Never includes the current {@link #mExpectedLifecycle}. */ 150 private List<String[]> mOtherPossibleLifecycles = new ArrayList<String[]>(2); 151 152 /** Map from lifecycle arrays to debugging log names. */ 153 private Map<String[], String> mLifecycleNames = new HashMap<String[], String>(2); 154 155 private String[] mExpectedReceivers = null; 156 private int mNextReceiver; 157 158 private String[] mExpectedData = null; 159 private boolean[] mReceivedData = null; 160 161 boolean mReceiverRegistered = false; 162 163 private static CallingTest sCallingTest = null; 164 165 public static void setCallingTest(CallingTest ct) { 166 sCallingTest = ct; 167 } 168 169 public LaunchpadActivity() { 170 } 171 172 @Override 173 protected void onCreate(Bundle icicle) { 174 super.onCreate(icicle); 175 176 resetLifecycles(); 177 178 // ON_STOP and ON_DESTROY are not tested because they may not be called. 179 180 final String action = getIntent().getAction(); 181 if (LIFECYCLE_BASIC.equals(action)) { 182 addPossibleLifecycle(LIFECYCLE_BASIC, new String[] { 183 ON_START, ON_RESUME, DO_FINISH, ON_PAUSE 184 }); 185 } else if (LIFECYCLE_SCREEN.equals(action)) { 186 addPossibleLifecycle(LIFECYCLE_SCREEN + "_RESTART", new String[] { 187 ON_START, ON_RESUME, DO_LOCAL_SCREEN, ON_PAUSE, 188 ON_RESTART, ON_START, ON_RESUME, DO_FINISH, ON_PAUSE 189 }); 190 addPossibleLifecycle(LIFECYCLE_SCREEN + "_RESUME", new String[] { 191 ON_START, ON_RESUME, DO_LOCAL_SCREEN, ON_PAUSE, 192 ON_RESUME, DO_FINISH, ON_PAUSE 193 }); 194 } else if (LIFECYCLE_DIALOG.equals(action)) { 195 addPossibleLifecycle(LIFECYCLE_DIALOG + "_RESTART", new String[] { 196 ON_START, ON_RESUME, DO_LOCAL_DIALOG, ON_PAUSE, 197 ON_RESTART, ON_START, ON_RESUME, DO_FINISH, ON_PAUSE 198 }); 199 addPossibleLifecycle(LIFECYCLE_DIALOG + "_RESUME", new String[] { 200 ON_START, ON_RESUME, DO_LOCAL_DIALOG, ON_PAUSE, 201 ON_RESUME, DO_FINISH, ON_PAUSE 202 }); 203 } 204 } 205 206 private void resetLifecycles() { 207 mNextLifecycle = 0; 208 mExpectedLifecycle = null; 209 mOtherPossibleLifecycles.clear(); 210 mLifecycleNames.clear(); 211 } 212 213 /** 214 * Add a potential lifecycle that this activity may follow, since there 215 * are usually multiple valid lifecycles. For instance, sometimes onPause 216 * will lead to onResume rather than onStop when another activity is 217 * raised over the current one. 218 * 219 * @param debugName for the lifecycle shown in the logs 220 * @param lifecycle array containing tokens indicating the expected lifecycle 221 */ 222 private void addPossibleLifecycle(String debugName, String[] lifecycle) { 223 mLifecycleNames.put(lifecycle, debugName); 224 if (mExpectedLifecycle == null) { 225 mExpectedLifecycle = lifecycle; 226 } else { 227 mOtherPossibleLifecycles.add(lifecycle); 228 } 229 } 230 231 /** 232 * Switch to the next possible lifecycle and return if switching was 233 * successful. Call this method when mExpectedLifecycle doesn't match 234 * the current lifecycle and you need to check another possible lifecycle. 235 * 236 * @return whether on not there was a lifecycle to switch to 237 */ 238 private boolean switchToNextPossibleLifecycle() { 239 if (!mOtherPossibleLifecycles.isEmpty()) { 240 String[] newLifecycle = mOtherPossibleLifecycles.remove(0); 241 Log.w(TAG, "Switching expected lifecycles from " 242 + mLifecycleNames.get(mExpectedLifecycle) + " to " 243 + mLifecycleNames.get(newLifecycle)); 244 mExpectedLifecycle = newLifecycle; 245 return true; 246 } else { 247 Log.w(TAG, "No more lifecycles after " 248 + mLifecycleNames.get(mExpectedLifecycle)); 249 mExpectedLifecycle = null; 250 return false; 251 } 252 } 253 254 @Override 255 protected void onStart() { 256 super.onStart(); 257 checkLifecycle(ON_START); 258 } 259 260 @Override 261 protected void onRestart() { 262 super.onStart(); 263 checkLifecycle(ON_RESTART); 264 } 265 266 @Override 267 protected void onResume() { 268 super.onResume(); 269 270 checkLifecycle(ON_RESUME); 271 272 if (!mStarted) { 273 mStarted = true; 274 275 mHandler.postDelayed(mTimeout, 5 * 1000); 276 277 final String action = getIntent().getAction(); 278 279 sCallingTest.startTiming(true); 280 281 if (LAUNCH.equals(action)) { 282 final Intent intent = getIntent(); 283 intent.setFlags(0); 284 intent.setComponent((ComponentName) intent.getParcelableExtra("component")); 285 startActivityForResult(intent, LAUNCHED_RESULT); 286 287 } else if (FORWARD_RESULT.equals(action)) { 288 final Intent intent = getIntent(); 289 intent.setFlags(0); 290 intent.setClass(this, LocalScreen.class); 291 startActivityForResult(intent, FORWARDED_RESULT); 292 } else if (BAD_PARCELABLE.equals(action)) { 293 mBadParcelable = true; 294 final Intent intent = getIntent(); 295 intent.setFlags(0); 296 intent.setClass(this, LocalScreen.class); 297 startActivityForResult(intent, LAUNCHED_RESULT); 298 } else if (BROADCAST_REGISTERED.equals(action)) { 299 setExpectedReceivers(new String[] { 300 RECEIVER_REG 301 }); 302 registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED)); 303 sCallingTest.addIntermediate("after-register"); 304 sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED)); 305 } else if (BROADCAST_LOCAL.equals(action)) { 306 setExpectedReceivers(new String[] { 307 RECEIVER_LOCAL 308 }); 309 sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL)); 310 } else if (BROADCAST_REMOTE.equals(action)) { 311 setExpectedReceivers(new String[] { 312 RECEIVER_REMOTE 313 }); 314 sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE)); 315 } else if (BROADCAST_ALL.equals(action)) { 316 setExpectedReceivers(new String[] { 317 RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL 318 }); 319 registerMyReceiver(new IntentFilter(BROADCAST_ALL)); 320 sCallingTest.addIntermediate("after-register"); 321 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); 322 } else if (BROADCAST_MULTI.equals(action)) { 323 setExpectedReceivers(new String[] { 324 RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE, 325 RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_REG, 326 RECEIVER_LOCAL, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_LOCAL, 327 RECEIVER_REMOTE, RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, 328 RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE, 329 RECEIVER_REG, RECEIVER_LOCAL, RECEIVER_REMOTE, RECEIVER_LOCAL, 330 RECEIVER_REMOTE, RECEIVER_LOCAL 331 }); 332 registerMyReceiver(new IntentFilter(BROADCAST_ALL)); 333 sCallingTest.addIntermediate("after-register"); 334 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); 335 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); 336 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); 337 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null); 338 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null); 339 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null); 340 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null); 341 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); 342 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); 343 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null); 344 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REPEAT), null); 345 } else if (BROADCAST_ABORT.equals(action)) { 346 setExpectedReceivers(new String[] { 347 RECEIVER_REMOTE, RECEIVER_ABORT 348 }); 349 registerMyReceiver(new IntentFilter(BROADCAST_ABORT)); 350 sCallingTest.addIntermediate("after-register"); 351 sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ABORT), null); 352 } else if (BROADCAST_STICKY1.equals(action)) { 353 setExpectedReceivers(new String[] { 354 RECEIVER_REG 355 }); 356 setExpectedData(new String[] { 357 DATA_1 358 }); 359 registerMyReceiver(new IntentFilter(BROADCAST_STICKY1)); 360 sCallingTest.addIntermediate("after-register"); 361 } else if (BROADCAST_STICKY2.equals(action)) { 362 setExpectedReceivers(new String[] { 363 RECEIVER_REG, RECEIVER_REG 364 }); 365 setExpectedData(new String[] { 366 DATA_1, DATA_2 367 }); 368 final IntentFilter filter = new IntentFilter(BROADCAST_STICKY1); 369 filter.addAction(BROADCAST_STICKY2); 370 registerMyReceiver(filter); 371 sCallingTest.addIntermediate("after-register"); 372 } else if (ALIAS_ACTIVITY.equals(action)) { 373 final Intent intent = getIntent(); 374 intent.setFlags(0); 375 intent.setClass(this, AliasActivityStub.class); 376 startActivityForResult(intent, LAUNCHED_RESULT); 377 } else if (EXPANDLIST_SELECT.equals(action)) { 378 final Intent intent = getIntent(); 379 intent.setFlags(0); 380 intent.setAction(action); 381 intent.setComponent((ComponentName) intent.getParcelableExtra("component")); 382 startActivityForResult(intent, LAUNCHED_RESULT); 383 } else if (EXPANDLIST_VIEW.equals(action)) { 384 final Intent intent = getIntent(); 385 intent.setFlags(0); 386 intent.setAction(action); 387 intent.setComponent((ComponentName) intent.getParcelableExtra("component")); 388 startActivityForResult(intent, LAUNCHED_RESULT); 389 } else if (EXPANDLIST_CALLBACK.equals(action)) { 390 final Intent intent = getIntent(); 391 intent.setFlags(0); 392 intent.setAction(action); 393 intent.setComponent((ComponentName) intent.getParcelableExtra("component")); 394 startActivityForResult(intent, LAUNCHED_RESULT); 395 } 396 } 397 } 398 399 @Override 400 protected void onSaveInstanceState(Bundle icicle) { 401 super.onSaveInstanceState(icicle); 402 if (mBadParcelable) { 403 icicle.putParcelable("baddy", new MyBadParcelable()); 404 } 405 } 406 407 @Override 408 protected void onPause() { 409 super.onPause(); 410 checkLifecycle(ON_PAUSE); 411 } 412 413 @Override 414 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 415 switch (requestCode) { 416 case LAUNCHED_RESULT: 417 sCallingTest.finishTiming(true); 418 finishWithResult(resultCode, data); 419 break; 420 case FORWARDED_RESULT: 421 sCallingTest.finishTiming(true); 422 if (RETURNED_RESULT.equals(data.getAction())) { 423 finishWithResult(resultCode, data); 424 } else { 425 finishWithResult(RESULT_CANCELED, new Intent().setAction("Bad data returned: " 426 + data)); 427 } 428 break; 429 default: 430 sCallingTest.finishTiming(true); 431 finishWithResult(RESULT_CANCELED, new Intent() 432 .setAction("Unexpected request code: " + requestCode)); 433 break; 434 } 435 } 436 437 private void checkLifecycle(String where) { 438 String action = getIntent().getAction(); 439 440 if (mExpectedLifecycle == null) { 441 return; 442 } 443 444 if (mNextLifecycle >= mExpectedLifecycle.length) { 445 finishBad("Activity lifecycle for " + action + " incorrect: received " + where 446 + " but don't expect any more calls"); 447 mExpectedLifecycle = null; 448 return; 449 } 450 451 do { 452 if (mExpectedLifecycle[mNextLifecycle].equals(where)) { 453 Log.w(TAG, "Matched: " + where); 454 break; 455 } else { 456 Log.w(TAG, "Expected " + mExpectedLifecycle[mNextLifecycle] + " but got " + where); 457 } 458 } while (switchToNextPossibleLifecycle()); 459 460 if (mExpectedLifecycle == null) { 461 finishBad("Activity lifecycle for " + action + " incorrect: received " + where 462 + " at " + mNextLifecycle); 463 return; 464 } 465 466 mNextLifecycle++; 467 468 if (mNextLifecycle >= mExpectedLifecycle.length) { 469 finishGood(); 470 return; 471 } 472 473 final String next = mExpectedLifecycle[mNextLifecycle]; 474 if (next.equals(DO_FINISH)) { 475 mNextLifecycle++; 476 if (mNextLifecycle >= mExpectedLifecycle.length) { 477 setTestResult(RESULT_OK, null); 478 } 479 if (!isFinishing()) { 480 finish(); 481 } 482 } else if (next.equals(DO_LOCAL_SCREEN)) { 483 mNextLifecycle++; 484 final Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH); 485 intent.setClass(this, LocalScreen.class); 486 startActivity(intent); 487 } else if (next.equals(DO_LOCAL_DIALOG)) { 488 mNextLifecycle++; 489 final Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH); 490 intent.setClass(this, LocalDialog.class); 491 startActivity(intent); 492 } 493 } 494 495 private void setExpectedReceivers(String[] receivers) { 496 mExpectedReceivers = receivers; 497 mNextReceiver = 0; 498 } 499 500 private void setExpectedData(String[] data) { 501 mExpectedData = data; 502 mReceivedData = new boolean[data.length]; 503 } 504 505 @SuppressWarnings("deprecation") 506 private Intent makeBroadcastIntent(String action) { 507 final Intent intent = new Intent(action, null); 508 intent.putExtra("caller", mCallTarget); 509 return intent; 510 } 511 512 private void finishGood() { 513 finishWithResult(RESULT_OK, null); 514 } 515 516 private void finishBad(String error) { 517 finishWithResult(RESULT_CANCELED, new Intent().setAction(error)); 518 } 519 520 private void finishWithResult(int resultCode, Intent data) { 521 setTestResult(resultCode, data); 522 finish(); 523 524 // Member fields set by calling setTestResult above... 525 sCallingTest.activityFinished(mResultCode, mData, mResultStack); 526 } 527 528 private void setTestResult(int resultCode, Intent data) { 529 mHandler.removeCallbacks(mTimeout); 530 unregisterMyReceiver(); 531 mResultCode = resultCode; 532 mData = data; 533 mResultStack = new RuntimeException("Original error was here"); 534 mResultStack.fillInStackTrace(); 535 } 536 537 private void registerMyReceiver(IntentFilter filter) { 538 mReceiverRegistered = true; 539 registerReceiver(mReceiver, filter); 540 } 541 542 private void unregisterMyReceiver() { 543 if (mReceiverRegistered) { 544 mReceiverRegistered = false; 545 unregisterReceiver(mReceiver); 546 } 547 } 548 549 private final Handler mHandler = new Handler() { 550 @Override 551 public void handleMessage(Message msg) { 552 } 553 }; 554 555 static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION; 556 static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1; 557 558 private final Binder mCallTarget = new Binder() { 559 @Override 560 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) { 561 data.setDataPosition(0); 562 data.enforceInterface(LaunchpadActivity.LAUNCH); 563 if (code == GOT_RECEIVE_TRANSACTION) { 564 final String name = data.readString(); 565 gotReceive(name, null); 566 return true; 567 } else if (code == ERROR_TRANSACTION) { 568 finishBad(data.readString()); 569 return true; 570 } 571 return false; 572 } 573 }; 574 575 private final void gotReceive(String name, Intent intent) { 576 synchronized (this) { 577 578 sCallingTest.addIntermediate(mNextReceiver + "-" + name); 579 580 if (mExpectedData != null) { 581 final int n = mExpectedData.length; 582 int i; 583 boolean prev = false; 584 for (i = 0; i < n; i++) { 585 if (mExpectedData[i].equals(intent.getStringExtra("test"))) { 586 if (mReceivedData[i]) { 587 prev = true; 588 continue; 589 } 590 mReceivedData[i] = true; 591 break; 592 } 593 } 594 if (i >= n) { 595 if (prev) { 596 finishBad("Receive got data too many times: " 597 + intent.getStringExtra("test")); 598 } else { 599 finishBad("Receive got unexpected data: " + intent.getStringExtra("test")); 600 } 601 return; 602 } 603 } 604 605 if (mNextReceiver >= mExpectedReceivers.length) { 606 finishBad("Got too many onReceiveIntent() calls!"); 607 } else if (!mExpectedReceivers[mNextReceiver].equals(name)) { 608 finishBad("Receive out of order: got " + name + " but expected " 609 + mExpectedReceivers[mNextReceiver] + " at " + mNextReceiver); 610 } else { 611 mNextReceiver++; 612 if (mNextReceiver == mExpectedReceivers.length) { 613 mHandler.post(mUnregister); 614 } 615 } 616 617 } 618 } 619 620 private final Runnable mUnregister = new Runnable() { 621 public void run() { 622 if (mReceiverRegistered) { 623 sCallingTest.addIntermediate("before-unregister"); 624 unregisterMyReceiver(); 625 } 626 sCallingTest.finishTiming(true); 627 finishGood(); 628 } 629 }; 630 631 private final Runnable mTimeout = new Runnable() { 632 public void run() { 633 String msg = "Timeout"; 634 if (mExpectedReceivers != null && mNextReceiver < mExpectedReceivers.length) { 635 msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver]; 636 } 637 finishBad(msg); 638 } 639 }; 640 641 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 642 @Override 643 public void onReceive(Context context, Intent intent) { 644 gotReceive(RECEIVER_REG, intent); 645 } 646 }; 647 } 648