am b6bddc2a: am 6ae71e50: am 506016a8: Merge "Make debug logging configurable via the logging setprop properties." into jb-mr1.1-dev

* commit 'b6bddc2aa5bb2cf093140e3b1dec6e387ecbc770':
  Make debug logging configurable via the logging setprop properties.
diff --git a/app-tests/Android.mk b/app-tests/Android.mk
new file mode 100644
index 0000000..c141484
--- /dev/null
+++ b/app-tests/Android.mk
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/app-tests/AppLaunchTest/Android.mk b/app-tests/AppLaunchTest/Android.mk
new file mode 100644
index 0000000..5e874d0
--- /dev/null
+++ b/app-tests/AppLaunchTest/Android.mk
@@ -0,0 +1,31 @@
+# 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.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := AppLaunchTest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SDK_VERSION := 8
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
+
diff --git a/app-tests/AppLaunchTest/AndroidManifest.xml b/app-tests/AppLaunchTest/AndroidManifest.xml
new file mode 100644
index 0000000..ef5f1ea
--- /dev/null
+++ b/app-tests/AppLaunchTest/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.applaunchtest" >
+
+    <instrumentation
+        android:name="com.android.applaunchtest.AppLaunchRunner"
+        android:targetPackage="com.android.applaunchtest" />
+
+    <application
+        android:label="@string/app_name" android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+</manifest>
diff --git a/app-tests/AppLaunchTest/res/values/strings.xml b/app-tests/AppLaunchTest/res/values/strings.xml
new file mode 100644
index 0000000..f8face5
--- /dev/null
+++ b/app-tests/AppLaunchTest/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+
+    <string name="app_name">AppLaunchTest</string>
+
+</resources>
diff --git a/app-tests/AppLaunchTest/src/com/android/applaunchtest/AppLaunchRunner.java b/app-tests/AppLaunchTest/src/com/android/applaunchtest/AppLaunchRunner.java
new file mode 100644
index 0000000..08d0894
--- /dev/null
+++ b/app-tests/AppLaunchTest/src/com/android/applaunchtest/AppLaunchRunner.java
@@ -0,0 +1,57 @@
+/*
+ * 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.applaunchtest;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+
+/**
+ * A special test runner that accepts arguments needed to run {@link AppLaunchTest}.
+ */
+public class AppLaunchRunner extends InstrumentationTestRunner {
+
+    private String mAppPackageName;
+    private long mWaitTime;
+
+    @Override
+    public void onCreate(Bundle args) {
+        mAppPackageName = args.getString("packageName");
+        String waitTimeString = args.getString("appLaunchWait");
+        if (waitTimeString != null) {
+            mWaitTime = Long.parseLong(waitTimeString);
+        } else {
+            // default to 7 seconds
+            mWaitTime = 7000;
+        }
+        super.onCreate(args);
+    }
+
+    /**
+     * Gets the Android application package name to launch. Application must have a launchable
+     * activity that handles MAIN intent.
+     */
+    public String getAppPackageName() {
+        return mAppPackageName;
+    }
+
+    /**
+     * Gets the number of ms to monitor for app crashes after attempting to launch the app.
+     */
+    public long getAppWaitTime() {
+        return mWaitTime;
+    }
+}
diff --git a/app-tests/AppLaunchTest/src/com/android/applaunchtest/AppLaunchTest.java b/app-tests/AppLaunchTest/src/com/android/applaunchtest/AppLaunchTest.java
new file mode 100644
index 0000000..257babc
--- /dev/null
+++ b/app-tests/AppLaunchTest/src/com/android/applaunchtest/AppLaunchTest.java
@@ -0,0 +1,319 @@
+/*
+ * 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.applaunchtest;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Simple tests that launches a specified app, and waits for a configurable amount of time for
+ * crashes and ANRs.
+ * <p/>
+ * If no crashes occur, test is considered passed.
+ * <p/>
+ * Derived from frameworks/base/tests/SmokeTests/... . TODO: consider refactoring to share code
+ */
+public class AppLaunchTest extends InstrumentationTestCase {
+
+    private static final String TAG = "AppLaunchTest";
+
+    private ActivityManager mActivityManager;
+    private PackageManager mPackageManager;
+    private String mPackageName;
+    private Context mContext;
+    private long mWaitTime;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getTargetContext();
+        assertNotNull("failed to get context", mContext);
+
+        mActivityManager = (ActivityManager)
+                mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        mPackageManager = mContext.getPackageManager();
+        assertNotNull("failed to get activity manager", mActivityManager);
+        assertNotNull("failed to get package manager", mPackageManager);
+
+        assertTrue("Unexpected runner: AppLaunchRunner must be used",
+                getInstrumentation() instanceof AppLaunchRunner);
+        AppLaunchRunner runner = (AppLaunchRunner)getInstrumentation();
+        mPackageName = runner.getAppPackageName();
+        mWaitTime  = runner.getAppWaitTime();
+        assertNotNull("package name to launch was not provided", mPackageName);
+        assertNotNull("time to wait for app launch was not provided", mWaitTime);
+    }
+
+    /**
+     * A test that runs Launcher-launchable activity for given package name and verifies that no
+     * ANRs or crashes happened while doing so.
+     */
+    public void testLaunchActivity() throws Exception {
+        final Set<ProcessError> errSet = new LinkedHashSet<ProcessError>();
+
+        ResolveInfo app = getLauncherActivity(mPackageName, mPackageManager);
+        assertNotNull(String.format("Could not find launchable activity for %s", mPackageName),
+                app);
+        final Collection<ProcessError> errProcs = runOneActivity(app, mWaitTime);
+        if (errProcs != null) {
+            errSet.addAll(errProcs);
+         }
+
+        if (!errSet.isEmpty()) {
+            fail(String.format("Detected %d errors on launch of app %s:\n%s", errSet.size(),
+                    mPackageName, reportWrappedListContents(errSet)));
+        }
+    }
+
+    /**
+     * 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()}.
+     * <p />
+     * The method will launch the app, wait for waitTime seconds, check for apps in the error state
+     * and then return.
+     */
+    public Collection<ProcessError> runOneActivity(ResolveInfo app, long appLaunchWait) {
+
+        Log.i(TAG, String.format("Running activity %s/%s", app.activityInfo.packageName,
+                app.activityInfo.name));
+
+        // We check for any Crash or ANR dialogs that are already up, and we ignore them.  This is
+        // so that we don't report crashes that were caused by prior apps.
+        final Collection<ProcessError> preErrProcs =
+                ProcessError.fromCollection(mActivityManager.getProcessesInErrorState());
+
+        // launch app, and waitfor it to start/settle
+        final Intent intent = intentForActivity(app);
+        mContext.startActivity(intent);
+        try {
+            Thread.sleep(appLaunchWait);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+
+        // TODO: inject event to see if app is responding. The smoke tests press 'Home', but
+        // we don't want to do that here because we want to take screenshot on app launch
+
+        // See if there are any errors.  We wait until down here to give ANRs as much time as
+        // possible to occur.
+        final Collection<ProcessError> errProcs =
+                ProcessError.fromCollection(mActivityManager.getProcessesInErrorState());
+
+        // Distinguish the asynchronous crashes/ANRs from the synchronous ones by checking the
+        // crash package name against the package name for {@code app}
+        if (errProcs != null) {
+            Iterator<ProcessError> errIter = errProcs.iterator();
+            while (errIter.hasNext()) {
+                ProcessError err = errIter.next();
+                if (!packageMatches(app, err)) {
+                    // crash in another package. Just log it for now
+                    Log.w(TAG, String.format("Detected crash in %s when launching %s",
+                            err.info.processName, app.activityInfo.packageName));
+                    errIter.remove();
+                }
+            }
+        }
+        // Take the difference between the remaining current error processes and the ones that were
+        // present when we started.  The result is guaranteed to be:
+        // 1) Errors that are pertinent to this app's package
+        // 2) Errors that are pertinent to this particular app invocation
+        if (errProcs != null && preErrProcs != null) {
+            errProcs.removeAll(preErrProcs);
+        }
+
+        return errProcs;
+    }
+
+    /**
+     * A helper function that checks whether the specified error could have been caused by the
+     * specified app.
+     *
+     * @param app The app to check against
+     * @param err The error that we're considering
+     */
+    private static boolean packageMatches(ResolveInfo app, ProcessError err) {
+        final String appPkg = app.activityInfo.packageName;
+        final String errPkg = err.info.processName;
+        Log.d(TAG, String.format("packageMatches(%s, %s)", appPkg, errPkg));
+        return appPkg.equals(errPkg);
+    }
+
+    /**
+     * A helper function to get the launchable activity for the given package name.
+     */
+    static ResolveInfo getLauncherActivity(String packageName, PackageManager pm) {
+        final Intent launchable = new Intent(Intent.ACTION_MAIN);
+        launchable.addCategory(Intent.CATEGORY_LAUNCHER);
+        launchable.setPackage(packageName);
+        return pm.resolveActivity(launchable, 0);
+    }
+
+    /**
+     * 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) {
+        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;
+    }
+
+    /**
+     * Report error reports for {@link ProcessErrorStateInfo} instances that are wrapped inside of
+     * {@link ProcessError} instances.  Just unwraps and calls
+     * {@see reportListContents(Collection<ProcessErrorStateInfo>)}.
+     */
+    static String reportWrappedListContents(Collection<ProcessError> errList) {
+        List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size());
+        for (ProcessError err : errList) {
+            newList.add(err.info);
+        }
+        return reportListContents(newList);
+    }
+
+    /**
+     * This helper function will dump the actual error reports.
+     *
+     * @param errList The error report containing one or more error records.
+     * @return Returns a string containing all of the errors.
+     */
+    private static String reportListContents(Collection<ProcessErrorStateInfo> errList) {
+        if (errList == null) return null;
+
+        StringBuilder builder = new StringBuilder();
+
+        Iterator<ProcessErrorStateInfo> iter = errList.iterator();
+        while (iter.hasNext()) {
+            ProcessErrorStateInfo entry = iter.next();
+
+            String condition;
+            switch (entry.condition) {
+            case ActivityManager.ProcessErrorStateInfo.CRASHED:
+                condition = "a CRASH";
+                break;
+            case ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING:
+                condition = "an ANR";
+                break;
+            default:
+                condition = "an unknown error";
+                break;
+            }
+
+            builder.append(String.format("Process %s encountered %s (%s)", entry.processName,
+                    condition, entry.shortMsg));
+            if (entry.condition == ActivityManager.ProcessErrorStateInfo.CRASHED) {
+                builder.append(String.format(" with stack trace:\n%s\n", entry.stackTrace));
+            }
+            builder.append("\n");
+        }
+        return builder.toString();
+    }
+
+    /**
+     * A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent
+     * crashes are considered equal).
+     */
+    static class ProcessError {
+        public final ProcessErrorStateInfo info;
+
+        public ProcessError(ProcessErrorStateInfo newInfo) {
+            info = newInfo;
+        }
+
+        public static Collection<ProcessError> fromCollection(Collection<ProcessErrorStateInfo> in)
+                {
+            if (in == null) {
+                return null;
+            }
+
+            List<ProcessError> out = new ArrayList<ProcessError>(in.size());
+            for (ProcessErrorStateInfo info : in) {
+                out.add(new ProcessError(info));
+            }
+            return out;
+        }
+
+        private boolean strEquals(String a, String b) {
+            if ((a == null) && (b == null)) {
+                return true;
+            } else if ((a == null) || (b == null)) {
+                return false;
+            } else {
+                return a.equals(b);
+            }
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other == null) return false;
+            if (!(other instanceof ProcessError)) return false;
+            ProcessError peOther = (ProcessError) other;
+
+            return (info.condition == peOther.info.condition)
+                    && strEquals(info.longMsg, peOther.info.longMsg)
+                    && (info.pid == peOther.info.pid)
+                    && strEquals(info.processName, peOther.info.processName)
+                    && strEquals(info.shortMsg, peOther.info.shortMsg)
+                    && strEquals(info.stackTrace, peOther.info.stackTrace)
+                    && strEquals(info.tag, peOther.info.tag)
+                    && (info.uid == peOther.info.uid);
+        }
+
+        private int hash(Object obj) {
+            if (obj == null) {
+                return 13;
+            } else {
+                return obj.hashCode();
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            int code = 17;
+            code += info.condition;
+            code *= hash(info.longMsg);
+            code += info.pid;
+            code *= hash(info.processName);
+            code *= hash(info.shortMsg);
+            code *= hash(info.stackTrace);
+            code *= hash(info.tag);
+            code += info.uid;
+            return code;
+        }
+    }
+}
diff --git a/app-tests/README b/app-tests/README
new file mode 100644
index 0000000..248e72d
--- /dev/null
+++ b/app-tests/README
@@ -0,0 +1,2 @@
+Contains generic Android target tests that can be run against any application.
+
diff --git a/uiautomator/library/src/com/android/uiautomator/core/InteractionController.java b/uiautomator/library/src/com/android/uiautomator/core/InteractionController.java
index c97d5de..93a162e 100644
--- a/uiautomator/library/src/com/android/uiautomator/core/InteractionController.java
+++ b/uiautomator/library/src/com/android/uiautomator/core/InteractionController.java
@@ -113,7 +113,7 @@
                     throw new IllegalStateException("Could not find provider: " + providerName);
                 }
                 provider = holder.provider;
-                cursor = provider.query(Settings.Secure.CONTENT_URI,
+                cursor = provider.query(null, Settings.Secure.CONTENT_URI,
                         new String[] {Settings.Secure.VALUE}, "name=?",
                         new String[] {Settings.Secure.LONG_PRESS_TIMEOUT}, null, null);
                 if (cursor.moveToFirst()) {