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