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
17package android.app.cts;
18
19import android.app.Activity;
20import android.content.BroadcastReceiver;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.os.Binder;
26import android.os.Bundle;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.Message;
30import android.os.Parcel;
31import android.os.Parcelable;
32import android.test.PerformanceTestCase;
33import android.util.Log;
34
35import java.util.ArrayList;
36import java.util.HashMap;
37import java.util.List;
38import java.util.Map;
39
40class 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
68public 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, 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
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            Log.i(TAG, "timeout");
634            String msg = "Timeout";
635            if (mExpectedReceivers != null && mNextReceiver < mExpectedReceivers.length) {
636                msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
637            }
638            finishBad(msg);
639        }
640    };
641
642    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
643        @Override
644        public void onReceive(Context context, Intent intent) {
645            gotReceive(RECEIVER_REG, intent);
646        }
647    };
648}
649