blob: 766245600d13b3cc9d14c9591dd2a6fd232f45ec [file] [log] [blame]
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.activity;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.test.PerformanceTestCase;
import android.util.Log;
class MyBadParcelable implements Parcelable {
public MyBadParcelable() {
}
public void writeToParcel(Parcel out, int flags) {
out.writeString("I am bad");
}
public int describeContents() {
return 0;
}
public static final Parcelable.Creator<MyBadParcelable> CREATOR
= new Parcelable.Creator<MyBadParcelable>() {
public MyBadParcelable createFromParcel(Parcel in) {
return new MyBadParcelable(in);
}
public MyBadParcelable[] newArray(int size) {
return new MyBadParcelable[size];
}
};
public MyBadParcelable(Parcel in) {
String nm = in.readString();
}
}
public class LaunchpadActivity extends Activity {
public interface CallingTest extends PerformanceTestCase.Intermediates {
public void startTiming(boolean realTime);
public void addIntermediate(String name);
public void addIntermediate(String name, long timeInNS);
public void finishTiming(boolean realTime);
public void activityFinished(int resultCode, Intent data,
RuntimeException where);
}
// Also used as the Binder interface descriptor string in these tests
public static final String LAUNCH = "com.android.frameworks.coretests.activity.LAUNCH";
public static final String FORWARD_RESULT =
"com.android.frameworks.coretests.activity.FORWARD_RESULT";
public static final String RETURNED_RESULT =
"com.android.frameworks.coretests.activity.RETURNED_RESULT";
public static final String BAD_PARCELABLE =
"comcom.android.frameworks.coretests.activity.BAD_PARCELABLE";
public static final int LAUNCHED_RESULT = 1;
public static final int FORWARDED_RESULT = 2;
public static final String LIFECYCLE_BASIC =
"com.android.frameworks.coretests.activity.LIFECYCLE_BASIC";
public static final String LIFECYCLE_SCREEN =
"com.android.frameworks.coretests.activity.LIFECYCLE_SCREEN";
public static final String LIFECYCLE_DIALOG =
"com.android.frameworks.coretests.activity.LIFECYCLE_DIALOG";
public static final String LIFECYCLE_FINISH_CREATE =
"com.android.frameworks.coretests.activity.LIFECYCLE_FINISH_CREATE";
public static final String LIFECYCLE_FINISH_START =
"com.android.frameworks.coretests.activity.LIFECYCLE_FINISH_START";
public static final String BROADCAST_REGISTERED =
"com.android.frameworks.coretests.activity.BROADCAST_REGISTERED";
public static final String BROADCAST_LOCAL =
"com.android.frameworks.coretests.activity.BROADCAST_LOCAL";
public static final String BROADCAST_REMOTE =
"com.android.frameworks.coretests.activity.BROADCAST_REMOTE";
public static final String BROADCAST_ALL =
"com.android.frameworks.coretests.activity.BROADCAST_ALL";
public static final String BROADCAST_REPEAT =
"com.android.frameworks.coretests.activity.BROADCAST_REPEAT";
public static final String BROADCAST_MULTI =
"com.android.frameworks.coretests.activity.BROADCAST_MULTI";
public static final String BROADCAST_ABORT =
"com.android.frameworks.coretests.activity.BROADCAST_ABORT";
public static final String BROADCAST_STICKY1 =
"com.android.frameworks.coretests.activity.BROADCAST_STICKY1";
public static final String BROADCAST_STICKY2 =
"com.android.frameworks.coretests.activity.BROADCAST_STICKY2";
public static final String RECEIVER_REG = "receiver-reg";
public static final String RECEIVER_LOCAL = "receiver-local";
public static final String RECEIVER_REMOTE = "receiver-remote";
public static final String RECEIVER_ABORT = "receiver-abort";
public static final String DATA_1 = "one";
public static final String DATA_2 = "two";
public static final String ON_START = "onStart";
public static final String ON_RESTART = "onRestart";
public static final String ON_RESUME = "onResume";
public static final String ON_FREEZE = "onSaveInstanceState";
public static final String ON_PAUSE = "onPause";
public static final String ON_STOP = "onStop";
public static final String ON_DESTROY = "onDestroy";
public static final String DO_FINISH = "finish";
public static final String DO_LOCAL_SCREEN = "local-screen";
public static final String DO_LOCAL_DIALOG = "local-dialog";
private boolean mBadParcelable = false;
private boolean mStarted = false;
private long mStartTime;
private int mResultCode = RESULT_CANCELED;
private Intent mData = (new Intent()).setAction("No result received");
private RuntimeException mResultStack = null;
private String[] mExpectedLifecycle = null;
private int mNextLifecycle;
private String[] mExpectedReceivers = null;
private int mNextReceiver;
private String[] mExpectedData = null;
private boolean[] mReceivedData = null;
boolean mReceiverRegistered = false;
private static CallingTest sCallingTest = null;
public static void setCallingTest(CallingTest ct) {
sCallingTest = ct;
}
public LaunchpadActivity() {
mStartTime = System.currentTimeMillis();
}
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
String action = getIntent().getAction();
if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "CREATE lauchpad "
+ Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
if (LIFECYCLE_BASIC.equals(action)) {
setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
} else if (LIFECYCLE_SCREEN.equals(action)) {
setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
DO_LOCAL_SCREEN, ON_FREEZE, ON_PAUSE, ON_STOP,
ON_RESTART, ON_START, ON_RESUME,
DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
} else if (LIFECYCLE_DIALOG.equals(action)) {
setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
DO_LOCAL_DIALOG, ON_FREEZE, ON_PAUSE, ON_RESUME,
DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
} else if (LIFECYCLE_FINISH_CREATE.equals(action)) {
// This one behaves a little differently when running in a group.
if (getParent() == null) {
setExpectedLifecycle(new String[]{ON_DESTROY});
} else {
setExpectedLifecycle(new String[]{ON_START, ON_STOP, ON_DESTROY});
}
finish();
} else if (LIFECYCLE_FINISH_START.equals(action)) {
setExpectedLifecycle(new String[]{ON_START, DO_FINISH,
ON_STOP, ON_DESTROY});
}
}
@Override
protected void onStart() {
super.onStart();
if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "START lauchpad "
+ Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
checkLifecycle(ON_START);
}
@Override
protected void onRestart() {
super.onStart();
checkLifecycle(ON_RESTART);
}
@Override
protected void onResume() {
super.onResume();
if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "RESUME lauchpad "
+ Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
checkLifecycle(ON_RESUME);
if (!mStarted) {
mStarted = true;
mHandler.postDelayed(mTimeout, 5 * 1000);
String action = getIntent().getAction();
sCallingTest.startTiming(true);
if (LAUNCH.equals(action)) {
Intent intent = getIntent();
intent.setFlags(0);
intent.setComponent((ComponentName)
intent.getParcelableExtra("component"));
//System.out.println("*** Launchpad is starting: comp=" + intent.component);
startActivityForResult(intent, LAUNCHED_RESULT);
} else if (FORWARD_RESULT.equals(action)) {
Intent intent = getIntent();
intent.setFlags(0);
intent.setClass(this, LocalScreen.class);
startActivityForResult(intent, FORWARDED_RESULT);
} else if (BAD_PARCELABLE.equals(action)) {
mBadParcelable = true;
Intent intent = getIntent();
intent.setFlags(0);
intent.setClass(this, LocalScreen.class);
startActivityForResult(intent, LAUNCHED_RESULT);
} else if (BROADCAST_REGISTERED.equals(action)) {
setExpectedReceivers(new String[]{RECEIVER_REG});
registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED));
sCallingTest.addIntermediate("after-register");
sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
} else if (BROADCAST_LOCAL.equals(action)) {
setExpectedReceivers(new String[]{RECEIVER_LOCAL});
sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL));
} else if (BROADCAST_REMOTE.equals(action)) {
setExpectedReceivers(new String[]{RECEIVER_REMOTE});
sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE));
} else if (BROADCAST_ALL.equals(action)) {
setExpectedReceivers(new String[]{
RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL});
registerMyReceiver(new IntentFilter(BROADCAST_ALL));
sCallingTest.addIntermediate("after-register");
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
} else if (BROADCAST_MULTI.equals(action)) {
setExpectedReceivers(new String[]{
RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
RECEIVER_LOCAL, RECEIVER_REMOTE,
RECEIVER_LOCAL, RECEIVER_REMOTE,
RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
RECEIVER_REMOTE, RECEIVER_LOCAL,
RECEIVER_REMOTE, RECEIVER_LOCAL});
registerMyReceiver(new IntentFilter(BROADCAST_ALL));
sCallingTest.addIntermediate("after-register");
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REPEAT), null);
} else if (BROADCAST_ABORT.equals(action)) {
setExpectedReceivers(new String[]{
RECEIVER_REMOTE, RECEIVER_ABORT});
registerMyReceiver(new IntentFilter(BROADCAST_ABORT));
sCallingTest.addIntermediate("after-register");
sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ABORT), null);
} else if (BROADCAST_STICKY1.equals(action)) {
setExpectedReceivers(new String[]{RECEIVER_REG});
setExpectedData(new String[]{DATA_1});
registerMyReceiver(new IntentFilter(BROADCAST_STICKY1));
sCallingTest.addIntermediate("after-register");
} else if (BROADCAST_STICKY2.equals(action)) {
setExpectedReceivers(new String[]{RECEIVER_REG, RECEIVER_REG});
setExpectedData(new String[]{DATA_1, DATA_2});
IntentFilter filter = new IntentFilter(BROADCAST_STICKY1);
filter.addAction(BROADCAST_STICKY2);
registerMyReceiver(filter);
sCallingTest.addIntermediate("after-register");
}
}
}
@Override
protected void onSaveInstanceState(Bundle icicle) {
super.onSaveInstanceState(icicle);
checkLifecycle(ON_FREEZE);
if (mBadParcelable) {
icicle.putParcelable("baddy", new MyBadParcelable());
}
}
@Override
protected void onPause() {
super.onPause();
if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "PAUSE lauchpad "
+ Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
checkLifecycle(ON_PAUSE);
}
@Override
protected void onStop() {
super.onStop();
if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "STOP lauchpad "
+ Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
checkLifecycle(ON_STOP);
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
switch (requestCode) {
case LAUNCHED_RESULT:
sCallingTest.finishTiming(true);
finishWithResult(resultCode, data);
break;
case FORWARDED_RESULT:
sCallingTest.finishTiming(true);
if (RETURNED_RESULT.equals(data.getAction())) {
finishWithResult(resultCode, data);
} else {
finishWithResult(RESULT_CANCELED, (new Intent()).setAction(
"Bad data returned: " + data));
}
break;
default:
sCallingTest.finishTiming(true);
finishWithResult(RESULT_CANCELED, (new Intent()).setAction(
"Unexpected request code: " + requestCode));
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "DESTROY lauchpad "
+ Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
checkLifecycle(ON_DESTROY);
sCallingTest.activityFinished(mResultCode, mData, mResultStack);
}
private void setExpectedLifecycle(String[] lifecycle) {
mExpectedLifecycle = lifecycle;
mNextLifecycle = 0;
}
private void checkLifecycle(String where) {
if (mExpectedLifecycle == null) return;
if (mNextLifecycle >= mExpectedLifecycle.length) {
finishBad("Activity lifecycle incorrect: received " + where
+ " but don't expect any more calls");
mExpectedLifecycle = null;
return;
}
if (!mExpectedLifecycle[mNextLifecycle].equals(where)) {
finishBad("Activity lifecycle incorrect: received " + where
+ " but expected " + mExpectedLifecycle[mNextLifecycle]
+ " at " + mNextLifecycle);
mExpectedLifecycle = null;
return;
}
mNextLifecycle++;
if (mNextLifecycle >= mExpectedLifecycle.length) {
setTestResult(RESULT_OK, null);
return;
}
String next = mExpectedLifecycle[mNextLifecycle];
if (where.equals(ON_DESTROY)) {
finishBad("Activity lifecycle incorrect: received " + where
+ " but expected more actions (next is " + next + ")");
mExpectedLifecycle = null;
return;
} else if (next.equals(DO_FINISH)) {
mNextLifecycle++;
if (mNextLifecycle >= mExpectedLifecycle.length) {
setTestResult(RESULT_OK, null);
}
if (!isFinishing()) {
finish();
}
} else if (next.equals(DO_LOCAL_SCREEN)) {
mNextLifecycle++;
Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
intent.setClass(this, LocalScreen.class);
startActivity(intent);
} else if (next.equals(DO_LOCAL_DIALOG)) {
mNextLifecycle++;
Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
intent.setClass(this, LocalDialog.class);
startActivity(intent);
}
}
private void setExpectedReceivers(String[] receivers) {
mExpectedReceivers = receivers;
mNextReceiver = 0;
}
private void setExpectedData(String[] data) {
mExpectedData = data;
mReceivedData = new boolean[data.length];
}
private Intent makeBroadcastIntent(String action) {
Intent intent = new Intent(action, null);
intent.putExtra("caller", mCallTarget);
return intent;
}
private void finishGood() {
finishWithResult(RESULT_OK, null);
}
private void finishBad(String error) {
finishWithResult(RESULT_CANCELED, (new Intent()).setAction(error));
}
private void finishWithResult(int resultCode, Intent data) {
setTestResult(resultCode, data);
finish();
}
private void setTestResult(int resultCode, Intent data) {
mHandler.removeCallbacks(mTimeout);
unregisterMyReceiver();
mResultCode = resultCode;
mData = data;
mResultStack = new RuntimeException("Original error was here");
mResultStack.fillInStackTrace();
}
private void registerMyReceiver(IntentFilter filter) {
mReceiverRegistered = true;
//System.out.println("Registering: " + mReceiver);
registerReceiver(mReceiver, filter);
}
private void unregisterMyReceiver() {
if (mReceiverRegistered) {
mReceiverRegistered = false;
//System.out.println("Unregistering: " + mReceiver);
unregisterReceiver(mReceiver);
}
}
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
}
};
static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
private Binder mCallTarget = new Binder() {
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
data.setDataPosition(0);
data.enforceInterface(LaunchpadActivity.LAUNCH);
if (code == GOT_RECEIVE_TRANSACTION) {
String name = data.readString();
gotReceive(name, null);
return true;
} else if (code == ERROR_TRANSACTION) {
finishBad(data.readString());
return true;
}
return false;
}
};
private final void gotReceive(String name, Intent intent) {
synchronized (this) {
//System.out.println("Got receive: " + name);
//System.out.println(mNextReceiver + " in " + mExpectedReceivers);
//new RuntimeException("stack").printStackTrace();
sCallingTest.addIntermediate(mNextReceiver + "-" + name);
if (mExpectedData != null) {
int n = mExpectedData.length;
int i;
boolean prev = false;
for (i = 0; i < n; i++) {
if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
if (mReceivedData[i]) {
prev = true;
continue;
}
mReceivedData[i] = true;
break;
}
}
if (i >= n) {
if (prev) {
finishBad("Receive got data too many times: "
+ intent.getStringExtra("test"));
} else {
finishBad("Receive got unexpected data: "
+ intent.getStringExtra("test"));
}
return;
}
}
if (mNextReceiver >= mExpectedReceivers.length) {
finishBad("Got too many onReceiveIntent() calls!");
// System.out.println("Too many intents received: now at "
// + mNextReceiver + ", expect list: "
// + Arrays.toString(mExpectedReceivers));
} else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
finishBad("Receive out of order: got " + name + " but expected "
+ mExpectedReceivers[mNextReceiver] + " at "
+ mNextReceiver);
} else {
mNextReceiver++;
if (mNextReceiver == mExpectedReceivers.length) {
mHandler.post(mUnregister);
}
}
}
}
private Runnable mUnregister = new Runnable() {
public void run() {
if (mReceiverRegistered) {
sCallingTest.addIntermediate("before-unregister");
unregisterMyReceiver();
}
sCallingTest.finishTiming(true);
finishGood();
}
};
private Runnable mTimeout = new Runnable() {
public void run() {
Log.i("foo", "**** TIMEOUT");
String msg = "Timeout";
if (mExpectedReceivers != null
&& mNextReceiver < mExpectedReceivers.length) {
msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
}
finishBad(msg);
}
};
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
//System.out.println("Receive in: " + this + ": " + intent);
gotReceive(RECEIVER_REG, intent);
}
};
}