diff --git a/tests/SmokeTest/tests/AndroidManifest.xml b/tests/SmokeTest/tests/AndroidManifest.xml
index 517eb1ea9cb44..cad37c576ceb5 100644
--- a/tests/SmokeTest/tests/AndroidManifest.xml
+++ b/tests/SmokeTest/tests/AndroidManifest.xml
@@ -18,20 +18,30 @@
-
+
+
+
+
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
index 1a2dcb971bb80..3efd65885e5ae 100644
--- a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
@@ -16,8 +16,6 @@
package com.android.smoketest;
-import com.android.internal.os.RuntimeInit;
-
import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.content.Context;
@@ -42,10 +40,18 @@ import java.util.Set;
public class ProcessErrorsTest extends AndroidTestCase {
private static final String TAG = "ProcessErrorsTest";
-
+
+ private final Intent mHomeIntent;
+
protected ActivityManager mActivityManager;
protected PackageManager mPackageManager;
+ public ProcessErrorsTest() {
+ mHomeIntent = new Intent(Intent.ACTION_MAIN);
+ mHomeIntent.addCategory(Intent.CATEGORY_HOME);
+ mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -59,7 +65,7 @@ public class ProcessErrorsTest extends AndroidTestCase {
assertNotNull(mPackageManager);
}
- public void testNoProcessErrors() throws Exception {
+ public void testNoProcessErrorsAfterBoot() throws Exception {
final String reportMsg = checkForProcessErrors();
if (reportMsg != null) {
Log.w(TAG, reportMsg);
@@ -72,15 +78,79 @@ public class ProcessErrorsTest extends AndroidTestCase {
private String checkForProcessErrors() throws Exception {
List errList;
errList = mActivityManager.getProcessesInErrorState();
-
+
// note: this contains information about each process that is currently in an error
- // condition. if the list is empty (null) then "we're good".
-
+ // condition. if the list is empty (null) then "we're good".
+
// if the list is non-empty, then it's useful to report the contents of the list
final String reportMsg = reportListContents(errList);
return reportMsg;
}
+ /**
+ * A helper function to query the provided {@link PackageManager} for a list of Activities that
+ * can be launched from Launcher.
+ */
+ static List getLauncherActivities(PackageManager pm) {
+ final Intent launchable = new Intent(Intent.ACTION_MAIN);
+ launchable.addCategory(Intent.CATEGORY_LAUNCHER);
+ final List activities = pm.queryIntentActivities(launchable, 0);
+ return activities;
+ }
+
+ /**
+ * A helper function to create an {@link Intent} to run, given a {@link ResolveInfo} specifying
+ * an activity to be launched.
+ */
+ static Intent intentForActivity(ResolveInfo app) {
+ // build an Intent to launch the specified app
+ final ComponentName component = new ComponentName(app.activityInfo.packageName,
+ app.activityInfo.name);
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(component);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ return intent;
+ }
+
+ /**
+ * A method to run the specified Activity and return a {@link Collection} of the Activities that
+ * were in an error state, as listed by {@link ActivityManager.getProcessesInErrorState()}.
+ *
+ * The method will launch the app, wait for 7 seconds, check for apps in the error state, send
+ * the Home intent, wait for 2 seconds, and then return.
+ */
+ public Collection runOneActivity(ResolveInfo app) {
+ final long appLaunchWait = 7000;
+ final long homeLaunchWait = 2000;
+
+ Log.i(TAG, String.format("Running activity %s/%s", app.activityInfo.packageName,
+ app.activityInfo.name));
+
+ // launch app, and wait 7 seconds for it to start/settle
+ final Intent intent = intentForActivity(app);
+ getContext().startActivity(intent);
+ try {
+ Thread.sleep(appLaunchWait);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ // See if there are any errors
+ final Collection errProcs =
+ mActivityManager.getProcessesInErrorState();
+
+ // Send the "home" intent and wait 2 seconds for us to get there
+ getContext().startActivity(mHomeIntent);
+ try {
+ Thread.sleep(homeLaunchWait);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+
+ return errProcs;
+ }
+
/**
* A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes
* happened while doing so.
@@ -89,46 +159,12 @@ public class ProcessErrorsTest extends AndroidTestCase {
* FIXME: first app doesn't go away.
*/
public void testRunAllActivities() throws Exception {
- final Intent home = new Intent(Intent.ACTION_MAIN);
- home.addCategory(Intent.CATEGORY_HOME);
- home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- final Intent launchable = new Intent(Intent.ACTION_MAIN);
- launchable.addCategory(Intent.CATEGORY_LAUNCHER);
- final List activities = mPackageManager.queryIntentActivities(launchable, 0);
final Set errSet = new HashSet();
- for (ResolveInfo info : activities) {
- Log.i(TAG, String.format("Got %s/%s", info.activityInfo.packageName,
- info.activityInfo.name));
-
- // build an Intent to launch the app
- final ComponentName component = new ComponentName(info.activityInfo.packageName,
- info.activityInfo.name);
- final Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setComponent(component);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- // launch app, and wait 7 seconds for it to start/settle
- getContext().startActivity(intent);
- try {
- Thread.sleep(7000);
- } catch (InterruptedException e) {
- // ignore
- }
-
- // See if there are any errors
- Collection procs = mActivityManager.getProcessesInErrorState();
- if (procs != null) {
- errSet.addAll(ProcessError.fromCollection(procs));
- }
-
- // Send the "home" intent and wait 2 seconds for us to get there
- getContext().startActivity(home);
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- // ignore
+ for (ResolveInfo app : getLauncherActivities(mPackageManager)) {
+ final Collection errProcs = runOneActivity(app);
+ if (errProcs != null) {
+ errSet.addAll(ProcessError.fromCollection(errProcs));
}
}
@@ -138,7 +174,7 @@ public class ProcessErrorsTest extends AndroidTestCase {
}
}
- private String reportWrappedListContents(Collection errList) {
+ String reportWrappedListContents(Collection errList) {
List newList = new ArrayList(errList.size());
for (ProcessError err : errList) {
newList.add(err.info);
@@ -186,7 +222,7 @@ public class ProcessErrorsTest extends AndroidTestCase {
* A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent
* crashes are considered equal).
*/
- private static class ProcessError {
+ static class ProcessError {
public final ProcessErrorStateInfo info;
public ProcessError(ProcessErrorStateInfo newInfo) {
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java b/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java
new file mode 100644
index 0000000000000..40b11c5af4d9a
--- /dev/null
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/SmokeTestRunner.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 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 com.android.smoketest;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.test.InstrumentationTestRunner;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A special test runner which does a test-start for each app in a separate testcase
+ */
+public class SmokeTestRunner extends InstrumentationTestRunner {
+
+ private static final String SUITE_NAME = "Smoke Test Suite";
+
+ /**
+ * Returns a single testcase for each app to launch
+ */
+ @Override
+ public TestSuite getAllTests() {
+ final TestSuite suite = new TestSuite(SUITE_NAME);
+
+ final PackageManager pm = getTargetContext().getPackageManager();
+ final List apps = ProcessErrorsTest.getLauncherActivities(pm);
+
+ // FIXME: figure out some way to control the reported class names for these anonymous
+ // FIXME: class instances.
+
+ final TestCase setupTest = new ProcessErrorsTest() {
+ @Override
+ public void runTest() throws Exception {
+ testSetUpConditions();
+ }
+ };
+ setupTest.setName("testSetUpConditions");
+ suite.addTest(setupTest);
+
+ final TestCase postBootTest = new ProcessErrorsTest() {
+ @Override
+ public void runTest() throws Exception {
+ testNoProcessErrorsAfterBoot();
+ }
+ };
+ postBootTest.setName("testNoProcessErrorsAfterBoot");
+ suite.addTest(postBootTest);
+
+ for (final ResolveInfo app : apps) {
+ final TestCase appTest = new ProcessErrorsTest() {
+ @Override
+ public void runTest() throws Exception {
+ final Set errSet = new HashSet();
+ final Collection errProcs = runOneActivity(app);
+ if (errProcs != null) {
+ errSet.addAll(ProcessError.fromCollection(errProcs));
+ }
+
+ if (!errSet.isEmpty()) {
+ fail(String.format("Got %d errors: %s", errSet.size(),
+ reportWrappedListContents(errSet)));
+ }
+ }
+ };
+ appTest.setName(app.activityInfo.name);
+ suite.addTest(appTest);
+ }
+
+ return suite;
+ }
+}
+