Home | History | Annotate | Download | only in stubs
      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 {
     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         void startTiming(boolean realTime);
     71 
     72         void addIntermediate(String name);
     73 
     74         void addIntermediate(String name, long timeInNS);
     75 
     76         void finishTiming(boolean realTime);
     77 
     78         void activityRunning(Activity activity);
     79 
     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.LIFECYCLE_DIALOG";
     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 
    169     public static void setCallingTest(CallingTest ct) {
    170         sCallingTest = ct;
    171     }
    172 
    173     public LaunchpadActivity() {
    174     }
    175 
    176     @Override
    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 
    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      */
    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      */
    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
    259     protected void onStart() {
    260         super.onStart();
    261         checkLifecycle(ON_START);
    262     }
    263 
    264     @Override
    265     protected void onRestart() {
    266         super.onStart();
    267         checkLifecycle(ON_RESTART);
    268     }
    269 
    270     @Override
    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
    405     protected void onSaveInstanceState(Bundle icicle) {
    406         super.onSaveInstanceState(icicle);
    407         if (mBadParcelable) {
    408             icicle.putParcelable("baddy", new MyBadParcelable());
    409         }
    410     }
    411 
    412     @Override
    413     protected void onPause() {
    414         super.onPause();
    415         checkLifecycle(ON_PAUSE);
    416     }
    417 
    418     @Override
    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 
    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 
    500     private void setExpectedReceivers(String[] receivers) {
    501         mExpectedReceivers = receivers;
    502         mNextReceiver = 0;
    503     }
    504 
    505     private void setExpectedData(String[] data) {
    506         mExpectedData = data;
    507         mReceivedData = new boolean[data.length];
    508     }
    509 
    510     @SuppressWarnings("deprecation")
    511     private Intent makeBroadcastIntent(String action) {
    512         final Intent intent = new Intent(action, null);
    513         intent.putExtra("caller", mCallTarget);
    514         return intent;
    515     }
    516 
    517     private void finishGood() {
    518         finishWithResult(RESULT_OK, null);
    519     }
    520 
    521     private void finishBad(String error) {
    522         finishWithResult(RESULT_CANCELED, new Intent().setAction(error));
    523     }
    524 
    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 
    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 
    542     private void registerMyReceiver(IntentFilter filter) {
    543         mReceiverRegistered = true;
    544         registerReceiver(mReceiver, filter);
    545     }
    546 
    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 
    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