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