1/*
2 * Copyright (C) 2006 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.activity;
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
35class MyBadParcelable implements Parcelable {
36    public MyBadParcelable() {
37    }
38
39    public void writeToParcel(Parcel out, int flags) {
40        out.writeString("I am bad");
41    }
42
43    public int describeContents() {
44        return 0;
45    }
46
47    public static final Parcelable.Creator<MyBadParcelable> CREATOR
48            = new Parcelable.Creator<MyBadParcelable>() {
49        public MyBadParcelable createFromParcel(Parcel in) {
50            return new MyBadParcelable(in);
51        }
52
53        public MyBadParcelable[] newArray(int size) {
54            return new MyBadParcelable[size];
55        }
56    };
57
58    public MyBadParcelable(Parcel in) {
59        String nm = in.readString();
60    }
61}
62
63public class LaunchpadActivity extends Activity {
64    public interface CallingTest extends PerformanceTestCase.Intermediates {
65        public void startTiming(boolean realTime);
66        public void addIntermediate(String name);
67        public void addIntermediate(String name, long timeInNS);
68        public void finishTiming(boolean realTime);
69        public void activityFinished(int resultCode, Intent data,
70                RuntimeException where);
71    }
72
73    // Also used as the Binder interface descriptor string in these tests
74    public static final String LAUNCH = "com.android.frameworks.coretests.activity.LAUNCH";
75
76    public static final String FORWARD_RESULT =
77            "com.android.frameworks.coretests.activity.FORWARD_RESULT";
78    public static final String RETURNED_RESULT =
79            "com.android.frameworks.coretests.activity.RETURNED_RESULT";
80
81    public static final String BAD_PARCELABLE =
82            "comcom.android.frameworks.coretests.activity.BAD_PARCELABLE";
83
84    public static final int LAUNCHED_RESULT = 1;
85    public static final int FORWARDED_RESULT = 2;
86
87    public static final String LIFECYCLE_BASIC =
88            "com.android.frameworks.coretests.activity.LIFECYCLE_BASIC";
89    public static final String LIFECYCLE_SCREEN =
90            "com.android.frameworks.coretests.activity.LIFECYCLE_SCREEN";
91    public static final String LIFECYCLE_DIALOG =
92            "com.android.frameworks.coretests.activity.LIFECYCLE_DIALOG";
93    public static final String LIFECYCLE_FINISH_CREATE =
94            "com.android.frameworks.coretests.activity.LIFECYCLE_FINISH_CREATE";
95    public static final String LIFECYCLE_FINISH_START =
96            "com.android.frameworks.coretests.activity.LIFECYCLE_FINISH_START";
97
98    public static final String BROADCAST_REGISTERED =
99            "com.android.frameworks.coretests.activity.BROADCAST_REGISTERED";
100    public static final String BROADCAST_LOCAL =
101            "com.android.frameworks.coretests.activity.BROADCAST_LOCAL";
102    public static final String BROADCAST_REMOTE =
103            "com.android.frameworks.coretests.activity.BROADCAST_REMOTE";
104    public static final String BROADCAST_ALL =
105            "com.android.frameworks.coretests.activity.BROADCAST_ALL";
106    public static final String BROADCAST_REPEAT =
107        "com.android.frameworks.coretests.activity.BROADCAST_REPEAT";
108    public static final String BROADCAST_MULTI =
109            "com.android.frameworks.coretests.activity.BROADCAST_MULTI";
110    public static final String BROADCAST_ABORT =
111            "com.android.frameworks.coretests.activity.BROADCAST_ABORT";
112
113    public static final String BROADCAST_STICKY1 =
114            "com.android.frameworks.coretests.activity.BROADCAST_STICKY1";
115    public static final String BROADCAST_STICKY2 =
116            "com.android.frameworks.coretests.activity.BROADCAST_STICKY2";
117
118    public static final String RECEIVER_REG = "receiver-reg";
119    public static final String RECEIVER_LOCAL = "receiver-local";
120    public static final String RECEIVER_REMOTE = "receiver-remote";
121    public static final String RECEIVER_ABORT = "receiver-abort";
122
123    public static final String DATA_1 = "one";
124    public static final String DATA_2 = "two";
125
126    public static final String ON_START = "onStart";
127    public static final String ON_RESTART = "onRestart";
128    public static final String ON_RESUME = "onResume";
129    public static final String ON_FREEZE = "onSaveInstanceState";
130    public static final String ON_PAUSE = "onPause";
131    public static final String ON_STOP = "onStop";
132    public static final String ON_DESTROY = "onDestroy";
133
134    public static final String DO_FINISH = "finish";
135    public static final String DO_LOCAL_SCREEN = "local-screen";
136    public static final String DO_LOCAL_DIALOG = "local-dialog";
137
138    private boolean mBadParcelable = false;
139
140    private boolean mStarted = false;
141    private long mStartTime;
142
143    private int mResultCode = RESULT_CANCELED;
144    private Intent mData = (new Intent()).setAction("No result received");
145    private RuntimeException mResultStack = null;
146
147    private String[] mExpectedLifecycle = null;
148    private int mNextLifecycle;
149
150    private String[] mExpectedReceivers = null;
151    private int mNextReceiver;
152
153    private String[] mExpectedData = null;
154    private boolean[] mReceivedData = null;
155
156    boolean mReceiverRegistered = false;
157
158    private static CallingTest sCallingTest = null;
159
160    public static void setCallingTest(CallingTest ct) {
161        sCallingTest = ct;
162    }
163
164    public LaunchpadActivity() {
165        mStartTime = System.currentTimeMillis();
166    }
167
168    @Override
169    protected void onCreate(Bundle icicle) {
170        super.onCreate(icicle);
171        String action = getIntent().getAction();
172        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "CREATE lauchpad "
173                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
174        if (LIFECYCLE_BASIC.equals(action)) {
175            setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
176                    DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
177        } else if (LIFECYCLE_SCREEN.equals(action)) {
178            setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
179                    DO_LOCAL_SCREEN, ON_FREEZE, ON_PAUSE, ON_STOP,
180                    ON_RESTART, ON_START, ON_RESUME,
181                    DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
182        } else if (LIFECYCLE_DIALOG.equals(action)) {
183            setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
184                    DO_LOCAL_DIALOG, ON_FREEZE, ON_PAUSE, ON_RESUME,
185                    DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
186        } else if (LIFECYCLE_FINISH_CREATE.equals(action)) {
187            // This one behaves a little differently when running in a group.
188            if (getParent() == null) {
189                setExpectedLifecycle(new String[]{ON_DESTROY});
190            } else {
191                setExpectedLifecycle(new String[]{ON_START, ON_STOP, ON_DESTROY});
192            }
193            finish();
194        } else if (LIFECYCLE_FINISH_START.equals(action)) {
195            setExpectedLifecycle(new String[]{ON_START, DO_FINISH,
196                    ON_STOP, ON_DESTROY});
197        }
198    }
199
200    @Override
201    protected void onStart() {
202        super.onStart();
203        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "START lauchpad "
204                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
205        checkLifecycle(ON_START);
206    }
207
208    @Override
209    protected void onRestart() {
210        super.onStart();
211        checkLifecycle(ON_RESTART);
212    }
213
214    @Override
215    protected void onResume() {
216        super.onResume();
217
218        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "RESUME lauchpad "
219                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
220        checkLifecycle(ON_RESUME);
221
222        if (!mStarted) {
223            mStarted = true;
224
225            mHandler.postDelayed(mTimeout, 5 * 1000);
226
227            String action = getIntent().getAction();
228
229            sCallingTest.startTiming(true);
230
231            if (LAUNCH.equals(action)) {
232                Intent intent = getIntent();
233                intent.setFlags(0);
234                intent.setComponent((ComponentName)
235                        intent.getParcelableExtra("component"));
236                //System.out.println("*** Launchpad is starting: comp=" + intent.component);
237                startActivityForResult(intent, LAUNCHED_RESULT);
238            } else if (FORWARD_RESULT.equals(action)) {
239                Intent intent = getIntent();
240                intent.setFlags(0);
241                intent.setClass(this, LocalScreen.class);
242                startActivityForResult(intent, FORWARDED_RESULT);
243            } else if (BAD_PARCELABLE.equals(action)) {
244                mBadParcelable = true;
245                Intent intent = getIntent();
246                intent.setFlags(0);
247                intent.setClass(this, LocalScreen.class);
248                startActivityForResult(intent, LAUNCHED_RESULT);
249            } else if (BROADCAST_REGISTERED.equals(action)) {
250                setExpectedReceivers(new String[]{RECEIVER_REG});
251                registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED));
252                sCallingTest.addIntermediate("after-register");
253                sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
254            } else if (BROADCAST_LOCAL.equals(action)) {
255                setExpectedReceivers(new String[]{RECEIVER_LOCAL});
256                sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL));
257            } else if (BROADCAST_REMOTE.equals(action)) {
258                setExpectedReceivers(new String[]{RECEIVER_REMOTE});
259                sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE));
260            } else if (BROADCAST_ALL.equals(action)) {
261                setExpectedReceivers(new String[]{
262                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL});
263                registerMyReceiver(new IntentFilter(BROADCAST_ALL));
264                sCallingTest.addIntermediate("after-register");
265                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
266            } else if (BROADCAST_MULTI.equals(action)) {
267                setExpectedReceivers(new String[]{
268                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
269                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
270                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
271                        RECEIVER_LOCAL, RECEIVER_REMOTE,
272                        RECEIVER_LOCAL, RECEIVER_REMOTE,
273                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
274                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
275                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
276                        RECEIVER_REMOTE, RECEIVER_LOCAL,
277                        RECEIVER_REMOTE, RECEIVER_LOCAL});
278                registerMyReceiver(new IntentFilter(BROADCAST_ALL));
279                sCallingTest.addIntermediate("after-register");
280                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
281                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
282                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
283                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
284                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
285                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
286                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
287                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
288                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
289                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
290                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REPEAT), null);
291            } else if (BROADCAST_ABORT.equals(action)) {
292                setExpectedReceivers(new String[]{
293                        RECEIVER_REMOTE, RECEIVER_ABORT});
294                registerMyReceiver(new IntentFilter(BROADCAST_ABORT));
295                sCallingTest.addIntermediate("after-register");
296                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ABORT), null);
297            } else if (BROADCAST_STICKY1.equals(action)) {
298                setExpectedReceivers(new String[]{RECEIVER_REG});
299                setExpectedData(new String[]{DATA_1});
300                registerMyReceiver(new IntentFilter(BROADCAST_STICKY1));
301                sCallingTest.addIntermediate("after-register");
302            } else if (BROADCAST_STICKY2.equals(action)) {
303                setExpectedReceivers(new String[]{RECEIVER_REG, RECEIVER_REG});
304                setExpectedData(new String[]{DATA_1, DATA_2});
305                IntentFilter filter = new IntentFilter(BROADCAST_STICKY1);
306                filter.addAction(BROADCAST_STICKY2);
307                registerMyReceiver(filter);
308                sCallingTest.addIntermediate("after-register");
309            }
310        }
311    }
312
313    @Override
314    protected void onSaveInstanceState(Bundle icicle) {
315        super.onSaveInstanceState(icicle);
316        checkLifecycle(ON_FREEZE);
317        if (mBadParcelable) {
318            icicle.putParcelable("baddy", new MyBadParcelable());
319        }
320    }
321
322    @Override
323    protected void onPause() {
324        super.onPause();
325        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "PAUSE lauchpad "
326                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
327        checkLifecycle(ON_PAUSE);
328    }
329
330    @Override
331    protected void onStop() {
332        super.onStop();
333        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "STOP lauchpad "
334                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
335        checkLifecycle(ON_STOP);
336    }
337
338    @Override
339    protected void onActivityResult(int requestCode, int resultCode,
340            Intent data) {
341        switch (requestCode) {
342            case LAUNCHED_RESULT:
343                sCallingTest.finishTiming(true);
344                finishWithResult(resultCode, data);
345                break;
346            case FORWARDED_RESULT:
347                sCallingTest.finishTiming(true);
348                if (RETURNED_RESULT.equals(data.getAction())) {
349                    finishWithResult(resultCode, data);
350                } else {
351                    finishWithResult(RESULT_CANCELED, (new Intent()).setAction(
352                            "Bad data returned: " + data));
353                }
354                break;
355            default:
356                sCallingTest.finishTiming(true);
357                finishWithResult(RESULT_CANCELED, (new Intent()).setAction(
358                        "Unexpected request code: " + requestCode));
359                break;
360        }
361    }
362
363    @Override
364    protected void onDestroy() {
365        super.onDestroy();
366        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "DESTROY lauchpad "
367                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
368        checkLifecycle(ON_DESTROY);
369        sCallingTest.activityFinished(mResultCode, mData, mResultStack);
370    }
371
372    private void setExpectedLifecycle(String[] lifecycle) {
373        mExpectedLifecycle = lifecycle;
374        mNextLifecycle = 0;
375    }
376
377    private void checkLifecycle(String where) {
378        if (mExpectedLifecycle == null) return;
379
380        if (mNextLifecycle >= mExpectedLifecycle.length) {
381            finishBad("Activity lifecycle incorrect: received " + where
382                    + " but don't expect any more calls");
383            mExpectedLifecycle = null;
384            return;
385        }
386        if (!mExpectedLifecycle[mNextLifecycle].equals(where)) {
387            finishBad("Activity lifecycle incorrect: received " + where
388                    + " but expected " + mExpectedLifecycle[mNextLifecycle]
389                    + " at " + mNextLifecycle);
390            mExpectedLifecycle = null;
391            return;
392        }
393
394        mNextLifecycle++;
395
396        if (mNextLifecycle >= mExpectedLifecycle.length) {
397            setTestResult(RESULT_OK, null);
398            return;
399        }
400
401        String next = mExpectedLifecycle[mNextLifecycle];
402        if (where.equals(ON_DESTROY)) {
403            finishBad("Activity lifecycle incorrect: received " + where
404                    + " but expected more actions (next is " + next + ")");
405            mExpectedLifecycle = null;
406            return;
407        } else if (next.equals(DO_FINISH)) {
408            mNextLifecycle++;
409            if (mNextLifecycle >= mExpectedLifecycle.length) {
410                setTestResult(RESULT_OK, null);
411            }
412            if (!isFinishing()) {
413                finish();
414            }
415        } else if (next.equals(DO_LOCAL_SCREEN)) {
416            mNextLifecycle++;
417            Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
418            intent.setClass(this, LocalScreen.class);
419            startActivity(intent);
420        } else if (next.equals(DO_LOCAL_DIALOG)) {
421            mNextLifecycle++;
422            Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
423            intent.setClass(this, LocalDialog.class);
424            startActivity(intent);
425        }
426    }
427
428    private void setExpectedReceivers(String[] receivers) {
429        mExpectedReceivers = receivers;
430        mNextReceiver = 0;
431    }
432
433    private void setExpectedData(String[] data) {
434        mExpectedData = data;
435        mReceivedData = new boolean[data.length];
436    }
437
438    private Intent makeBroadcastIntent(String action) {
439        Intent intent = new Intent(action, null);
440        intent.putExtra("caller", mCallTarget);
441        return intent;
442    }
443
444    private void finishGood() {
445        finishWithResult(RESULT_OK, null);
446    }
447
448    private void finishBad(String error) {
449        finishWithResult(RESULT_CANCELED, (new Intent()).setAction(error));
450    }
451
452    private void finishWithResult(int resultCode, Intent data) {
453        setTestResult(resultCode, data);
454        finish();
455    }
456
457    private void setTestResult(int resultCode, Intent data) {
458        mHandler.removeCallbacks(mTimeout);
459        unregisterMyReceiver();
460        mResultCode = resultCode;
461        mData = data;
462        mResultStack = new RuntimeException("Original error was here");
463        mResultStack.fillInStackTrace();
464    }
465
466    private void registerMyReceiver(IntentFilter filter) {
467        mReceiverRegistered = true;
468        //System.out.println("Registering: " + mReceiver);
469        registerReceiver(mReceiver, filter);
470    }
471
472    private void unregisterMyReceiver() {
473        if (mReceiverRegistered) {
474            mReceiverRegistered = false;
475            //System.out.println("Unregistering: " + mReceiver);
476            unregisterReceiver(mReceiver);
477        }
478    }
479
480    private Handler mHandler = new Handler() {
481        public void handleMessage(Message msg) {
482        }
483    };
484
485    static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
486    static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
487
488    private Binder mCallTarget = new Binder() {
489        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
490            data.setDataPosition(0);
491            data.enforceInterface(LaunchpadActivity.LAUNCH);
492            if (code == GOT_RECEIVE_TRANSACTION) {
493                String name = data.readString();
494                gotReceive(name, null);
495                return true;
496            } else if (code == ERROR_TRANSACTION) {
497                finishBad(data.readString());
498                return true;
499            }
500            return false;
501        }
502    };
503
504    private final void gotReceive(String name, Intent intent) {
505        synchronized (this) {
506
507            //System.out.println("Got receive: " + name);
508            //System.out.println(mNextReceiver + " in " + mExpectedReceivers);
509            //new RuntimeException("stack").printStackTrace();
510
511            sCallingTest.addIntermediate(mNextReceiver + "-" + name);
512
513            if (mExpectedData != null) {
514                int n = mExpectedData.length;
515                int i;
516                boolean prev = false;
517                for (i = 0; i < n; i++) {
518                    if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
519                        if (mReceivedData[i]) {
520                            prev = true;
521                            continue;
522                        }
523                        mReceivedData[i] = true;
524                        break;
525                    }
526                }
527                if (i >= n) {
528                    if (prev) {
529                        finishBad("Receive got data too many times: "
530                                + intent.getStringExtra("test"));
531                    } else {
532                        finishBad("Receive got unexpected data: "
533                                + intent.getStringExtra("test"));
534                    }
535                    return;
536                }
537            }
538
539            if (mNextReceiver >= mExpectedReceivers.length) {
540                finishBad("Got too many onReceiveIntent() calls!");
541//                System.out.println("Too many intents received: now at "
542//                                   + mNextReceiver + ", expect list: "
543//                                   + Arrays.toString(mExpectedReceivers));
544            } else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
545                finishBad("Receive out of order: got " + name + " but expected "
546                        + mExpectedReceivers[mNextReceiver] + " at "
547                        + mNextReceiver);
548            } else {
549                mNextReceiver++;
550                if (mNextReceiver == mExpectedReceivers.length) {
551                    mHandler.post(mUnregister);
552                }
553            }
554
555        }
556    }
557
558    private Runnable mUnregister = new Runnable() {
559        public void run() {
560            if (mReceiverRegistered) {
561                sCallingTest.addIntermediate("before-unregister");
562                unregisterMyReceiver();
563            }
564            sCallingTest.finishTiming(true);
565            finishGood();
566        }
567    };
568
569    private Runnable mTimeout = new Runnable() {
570        public void run() {
571            Log.i("foo", "**** TIMEOUT");
572            String msg = "Timeout";
573            if (mExpectedReceivers != null
574                    && mNextReceiver < mExpectedReceivers.length) {
575                msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
576            }
577            finishBad(msg);
578        }
579    };
580
581    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
582        public void onReceive(Context context, Intent intent) {
583            //System.out.println("Receive in: " + this + ": " + intent);
584            gotReceive(RECEIVER_REG, intent);
585        }
586    };
587}
588
589