Home | History | Annotate | Download | only in cts
      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