Merge "EGL cleanup tests"
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index a4277fc..3887c1d 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -125,21 +125,23 @@
 	NativeMediaTest_XA
 
 cts_ui_tests := \
-        CtsUiAutomatorTests
+	CtsUiAutomatorTests
 
 # All the files that will end up under the repository/testcases
 # directory of the final CTS distribution.
 CTS_TEST_CASES := $(call cts-get-lib-paths,$(cts_host_libraries)) \
 		$(call cts-get-package-paths,$(cts_test_packages)) \
 		$(call cts-get-native-paths,$(cts_native_exes)) \
-		$(call cts-get-ui-lib-paths,$(cts_ui_tests))
+		$(call cts-get-ui-lib-paths,$(cts_ui_tests)) \
+		$(call cts-get-ui-lib-paths,$(PTS_UI_TESTS))
 
 # All the XMLs that will end up under the repository/testcases
 # and that need to be created before making the final CTS distribution.
 CTS_TEST_XMLS := $(call cts-get-test-xmls,$(cts_host_libraries)) \
 		$(call cts-get-test-xmls,$(cts_test_packages)) \
 		$(call cts-get-test-xmls,$(cts_native_exes)) \
-		$(call cts-get-test-xmls,$(cts_ui_tests))
+		$(call cts-get-test-xmls,$(cts_ui_tests)) \
+		$(call cts-get-test-xmls,$(PTS_UI_TESTS))
 
 
 # The following files will be placed in the tools directory of the CTS distribution
diff --git a/build/test_uiautomator.mk b/build/test_uiautomator.mk
index 255f70b..c17f12b 100644
--- a/build/test_uiautomator.mk
+++ b/build/test_uiautomator.mk
@@ -17,6 +17,8 @@
 # package XML needed by CTS.
 #
 
+LOCAL_DEX_PREOPT := false
+
 include $(BUILD_JAVA_LIBRARY)
 
 cts_library_xml := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).xml 
diff --git a/suite/pts/PtsBenchmarkingList.mk b/suite/pts/PtsBenchmarkingList.mk
index 7c0ad47..0aba241 100644
--- a/suite/pts/PtsBenchmarkingList.mk
+++ b/suite/pts/PtsBenchmarkingList.mk
@@ -29,8 +29,12 @@
 PTS_SUPPORT_PACKAGES := \
     PtsDeviceTaskswitchingAppA \
     PtsDeviceTaskswitchingAppB \
-    PtsDeviceTaskswitchingControl
+    PtsDeviceTaskswitchingControl \
+    PtsDeviceJankApp
 
 PTS_HOST_CASES := \
     PtsHostBootup \
     PtsHostUi
+
+PTS_UI_TESTS := \
+    PtsHostJank
diff --git a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/reference/GLGameActivity.java b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/reference/GLGameActivity.java
index 5fc1c1b..29b79f4 100644
--- a/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/reference/GLGameActivity.java
+++ b/suite/pts/deviceTests/opengl/src/com/android/pts/opengl/reference/GLGameActivity.java
@@ -56,8 +56,8 @@
         System.loadLibrary("ptsopengl_jni");
 
         Intent intent = getIntent();
-        mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 0);
-        mTimeout = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 0);
+        mNumFrames = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_NUM_FRAMES, 1000);
+        mTimeout = intent.getIntExtra(GLActivityIntentKeys.INTENT_EXTRA_TIMEOUT, 1000000);
 
         SurfaceView surfaceView = new SurfaceView(this);
         surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
diff --git a/suite/pts/hostTests/jank/Android.mk b/suite/pts/hostTests/jank/Android.mk
new file mode 100644
index 0000000..0a340f8
--- /dev/null
+++ b/suite/pts/hostTests/jank/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 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_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/local/tmp
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := PtsHostJank
+LOCAL_JAVA_LIBRARIES := uiautomator.core geppetto.tests.common
+LOCAL_STATIC_JAVA_LIBRARIES := com.android.uiautomator.platform.common
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_CTS_TEST_APK := PtsDeviceJankApp
+LOCAL_CTS_TEST_APP_PACKAGE := com.android.pts.opengl
+LOCAL_CTS_TEST_PACKAGE := com.android.pts.jank
+
+include $(BUILD_CTS_UI_JAVA_LIBRARY)
+
+# Build the test APK using its own makefile, and any other CTS-related packages
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/suite/pts/hostTests/jank/app/Android.mk b/suite/pts/hostTests/jank/app/Android.mk
new file mode 100644
index 0000000..257c552
--- /dev/null
+++ b/suite/pts/hostTests/jank/app/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 2013 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)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := ptsutil ctsutil ctstestrunner
+
+LOCAL_JNI_SHARED_LIBRARIES := libptsopengl_jni
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+# add the src of the reference benchmark
+LOCAL_SRC_FILES += $(call all-java-files-under, ../../../deviceTests/opengl/src)
+
+LOCAL_ASSET_DIR := $(LOCAL_PATH)/../../../deviceTests/opengl/assets
+
+LOCAL_PACKAGE_NAME := PtsDeviceJankApp
+
+LOCAL_SDK_VERSION := 16
+
+include $(BUILD_CTS_PACKAGE)
+
+
diff --git a/suite/pts/hostTests/jank/app/AndroidManifest.xml b/suite/pts/hostTests/jank/app/AndroidManifest.xml
new file mode 100644
index 0000000..e75fd7a
--- /dev/null
+++ b/suite/pts/hostTests/jank/app/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2013 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.pts.jank" >
+
+    <uses-feature
+        android:glEsVersion="0x00020000"
+        android:required="true" />
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+
+    <application>
+        <activity
+            android:name=".JankActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name="com.android.pts.opengl.reference.GLGameActivity"
+            android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
+            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankActivity.java b/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankActivity.java
new file mode 100644
index 0000000..2c37922
--- /dev/null
+++ b/suite/pts/hostTests/jank/app/src/com/android/pts/jank/JankActivity.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013 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.pts.jank;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.pts.opengl.reference.GLGameActivity;
+
+public class JankActivity extends Activity {
+    static final String TAG = "JankActivity";
+
+    private final static int GAME_ACTIVITY_CODE = 1;
+
+    public void onCreate(Bundle data) {
+        super.onCreate(data);
+        // Sets the view to be a big button. This is pressed by uiautomator when SurfaceFlinger's
+        // buffers have been cleared.
+        final Button start = new Button(this);
+        start.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                final Intent intent = new Intent(JankActivity.this, GLGameActivity.class);
+                startActivityForResult(intent, GAME_ACTIVITY_CODE);
+            }
+        });
+        setContentView(start);
+    }
+
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode == GAME_ACTIVITY_CODE) {
+            finish();
+        }
+    }
+}
diff --git a/suite/pts/hostTests/jank/src/com/android/pts/jank/PtsHostJankTest.java b/suite/pts/hostTests/jank/src/com/android/pts/jank/PtsHostJankTest.java
new file mode 100644
index 0000000..b12908a
--- /dev/null
+++ b/suite/pts/hostTests/jank/src/com/android/pts/jank/PtsHostJankTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2013 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.pts.jank;
+
+import android.util.Log;
+
+import com.android.uiautomator.core.UiDevice;
+import com.android.uiautomator.testrunner.UiAutomatorTestCase;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+import junit.framework.Assert;
+
+public class PtsHostJankTest extends UiAutomatorTestCase {
+    private static final String TAG = PtsHostJankTest.class.getSimpleName();
+    private static final int NUM_ITERATIONS = 5;
+    private static final String APP_WINDOW_NAME =
+            "SurfaceView";
+    private static final String LAUNCH_COMMAND =
+            "am start -a android.intent.action.MAIN -n com.android.pts.jank/.JankActivity -W";
+    private static final String CLEAR_BUFFER_CMD =
+            "dumpsys SurfaceFlinger --latency-clear " + APP_WINDOW_NAME;
+    private static final String FRAME_LATENCY_CMD =
+            "dumpsys SurfaceFlinger --latency " + APP_WINDOW_NAME;
+    private static final long PENDING_FENCE_TIMESTAMP = (1L << 63) - 1;
+
+    public void testGLReferenceBenchmark() throws Exception {
+        // Launch the app.
+        runShellCommand(LAUNCH_COMMAND);
+
+        // Wait till the device is idle.
+        UiDevice device = UiDevice.getInstance();
+        device.waitForIdle();
+
+        // This is batch is important because this is where jank caused by loading textures and
+        // meshes will be encountered. It also needs to be separated from the loop so that the
+        // start button can be pressed.
+        clearBuffer();
+        // Touch screen, which starts the rendering.
+        int width = device.getDisplayWidth();
+        int height = device.getDisplayHeight();
+        device.click(width / 2, height / 2);
+        Thread.sleep(2000);
+        dumpBuffer();
+
+        // Loop because SurfaceFlinger's buffer is small.
+        for (int i = 0; i < NUM_ITERATIONS; i++) {
+            clearBuffer();
+            Thread.sleep(2000);
+            dumpBuffer();
+        }
+    }
+
+    private void clearBuffer() throws Exception {
+        // Clear SurfaceFlinger latency buffer.
+        Process p = null;
+        try {
+            p = runShellCommand(CLEAR_BUFFER_CMD);
+        } finally {
+            if (p != null) {
+                p.destroy();
+                p = null;
+            }
+        }
+    }
+
+    private void dumpBuffer() throws Exception {
+        // Dump SurfaceFlinger latency buffer.
+        Process p = null;
+        try {
+            p = runShellCommand(FRAME_LATENCY_CMD);
+            BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
+            String line = reader.readLine();
+            long refreshPeriod = Long.parseLong(line.trim());
+            while ((line = reader.readLine()) != null) {
+                String[] values = line.split("\\s+");
+                if (values.length == 3) {
+                    long timestamp = Long.parseLong(values[1]);
+                    if (timestamp != PENDING_FENCE_TIMESTAMP && timestamp != 0) {
+                        Log.i(TAG, "Timestamp: " + timestamp);
+                    }
+                }
+            }
+        } finally {
+            if (p != null) {
+                p.destroy();
+                p = null;
+            }
+        }
+    }
+
+    private Process runShellCommand(String command) throws Exception {
+        Process p = Runtime.getRuntime().exec(command);
+        int status = p.waitFor();
+        if (status != 0) {
+            throw new RuntimeException(
+                    String.format("Run shell command: %s, status: %s", command, status));
+        }
+        return p;
+    }
+}
diff --git a/tests/src/android/text/method/cts/KeyListenerStubActivity.java b/tests/src/android/text/method/cts/KeyListenerStubActivity.java
index f831af9..149ad87 100644
--- a/tests/src/android/text/method/cts/KeyListenerStubActivity.java
+++ b/tests/src/android/text/method/cts/KeyListenerStubActivity.java
@@ -20,6 +20,7 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.os.SystemClock;
 import android.text.method.BaseKeyListener;
 import android.text.method.DateKeyListener;
 import android.text.method.DateTimeKeyListener;
@@ -29,6 +30,7 @@
 import android.text.method.QwertyKeyListener;
 import android.text.method.TextKeyListener;
 import android.text.method.TimeKeyListener;
+import android.util.Log;
 
 /**
  * This Activity is used for testing:
@@ -54,9 +56,47 @@
  */
 
 public class KeyListenerStubActivity extends Activity {
+    private boolean mHasWindowFocus = false;
+    private Object mHasWindowFocusLock = new Object();
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.keylistener_layout);
     }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (!hasFocus) {
+            Log.w("KeyListenerStubActivity", "KeyListenerStubActivity lost window focus");
+        }
+        synchronized(mHasWindowFocusLock) {
+            mHasWindowFocus = hasFocus;
+            mHasWindowFocusLock.notify();
+        }
+    }
+
+    /**
+     * Blocks the calling thread until the {@link KeyListenerStubActivity} has window focus or the
+     * specified duration (in milliseconds) has passed.
+     */
+    public boolean waitForWindowFocus(long durationMillis) {
+        long elapsedMillis = SystemClock.elapsedRealtime();
+        synchronized(mHasWindowFocusLock) {
+            mHasWindowFocus = hasWindowFocus();
+            while (!mHasWindowFocus && durationMillis > 0) {
+                long newElapsedMillis = SystemClock.elapsedRealtime();
+                durationMillis -= (newElapsedMillis - elapsedMillis);
+                elapsedMillis = newElapsedMillis;
+                if (durationMillis > 0) {
+                    try {
+                        mHasWindowFocusLock.wait(durationMillis);
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+            return mHasWindowFocus;
+        }
+    }
 }
diff --git a/tests/src/android/view/cts/ViewTestStubActivity.java b/tests/src/android/view/cts/ViewTestStubActivity.java
index 9809962..69676cb 100644
--- a/tests/src/android/view/cts/ViewTestStubActivity.java
+++ b/tests/src/android/view/cts/ViewTestStubActivity.java
@@ -18,12 +18,52 @@
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
 import com.android.cts.stub.R;
 
 public class ViewTestStubActivity extends Activity {
+    private boolean mHasWindowFocus = false;
+    private Object mHasWindowFocusLock = new Object();
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         setContentView(R.layout.view_layout);
     }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (!hasFocus) {
+            Log.w("ViewTestStubActivity", "ViewTestStubActivity lost window focus");
+        }
+        synchronized(mHasWindowFocusLock) {
+            mHasWindowFocus = hasFocus;
+            mHasWindowFocusLock.notify();
+        }
+    }
+
+    /**
+     * Blocks the calling thread until the {@link ViewTestStubActivity} has window focus or the
+     * specified duration (in milliseconds) has passed.
+     */
+    public boolean waitForWindowFocus(long durationMillis) {
+        long elapsedMillis = SystemClock.elapsedRealtime();
+        synchronized(mHasWindowFocusLock) {
+            mHasWindowFocus = hasWindowFocus();
+            while (!mHasWindowFocus && durationMillis > 0) {
+                long newElapsedMillis = SystemClock.elapsedRealtime();
+                durationMillis -= (newElapsedMillis - elapsedMillis);
+                elapsedMillis = newElapsedMillis;
+                if (durationMillis > 0) {
+                    try {
+                        mHasWindowFocusLock.wait(durationMillis);
+                    } catch (InterruptedException e) {
+                    }
+                }
+            }
+            return mHasWindowFocus;
+        }
+    }
 }
diff --git a/tests/tests/content/src/android/content/cts/IntentFilterTest.java b/tests/tests/content/src/android/content/cts/IntentFilterTest.java
index 87a1834..d067b9e 100644
--- a/tests/tests/content/src/android/content/cts/IntentFilterTest.java
+++ b/tests/tests/content/src/android/content/cts/IntentFilterTest.java
@@ -61,6 +61,7 @@
     private static final String CATEGORY = "testCategory";
     private static final String DATA_TYPE = "vnd.android.cursor.dir/person";
     private static final String DATA_SCHEME = "testDataSchemes.";
+    private static final String SSP = "testSsp";
     private static final String HOST = "testHost";
     private static final int PORT = 80;
     private static final String DATA_PATH = "testDataPath";
@@ -260,6 +261,173 @@
         verifyContent(filter, ACTION, DATA_TYPE);
     }
 
+
+    public void testSchemeSpecificParts() throws Exception {
+        IntentFilter filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"ssp1", "2ssp"},
+                new int[]{PATTERN_LITERAL, PATTERN_LITERAL});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ssp1"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:2ssp"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:ssp"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:ssp12"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"ssp1", "2ssp"},
+                new int[]{PATTERN_PREFIX, PATTERN_PREFIX});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ssp1"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:2ssp"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:ssp"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ssp12"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"ssp.*"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ssp1"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ssp"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:ss"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{".*"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ssp1"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ssp"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"a1*b"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a1b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a11b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a2b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a1bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"a1*"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a1"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a11"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a1b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a11"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a2"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"a\\.*b"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a.b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a..b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a2b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a.bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"a.*b"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a.b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a.1b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a2b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a.bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"a.*"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a.b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a.1b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a2b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a.bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"a.\\*b"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a.*b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a1*b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a2b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a.bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:"), });
+        filter = new Match(null, null, null, new String[]{"scheme"},
+                null, null, null, null, new String[]{"a.\\*"},
+                new int[]{PATTERN_SIMPLE_GLOB});
+        checkMatches(filter, new MatchCondition[] {
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a.*"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART, null, null, null,
+                        "scheme:a1*"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null, null, null,
+                        "scheme:a1b"), });
+    }
+
     public void testAuthorities() {
         for (int i = 0; i < 10; i++) {
             mIntentFilter.addDataAuthority(HOST + i, String.valueOf(PORT + i));
@@ -770,6 +938,17 @@
                 }
             }
         }
+
+        Match(String[] actions, String[] categories, String[] mimeTypes, String[] schemes,
+                String[] authorities, String[] ports, String[] paths, int[] pathTypes,
+                String[] ssps, int[] sspTypes) {
+            this(actions, categories, mimeTypes, schemes, authorities, ports, paths, pathTypes);
+            if (ssps != null) {
+                for (int i = 0; i < ssps.length; i++) {
+                    addDataSchemeSpecificPart(ssps[i], sspTypes[i]);
+                }
+            }
+        }
     }
 
     private static class MatchCondition {
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 7852576..633d5d7 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -755,7 +755,9 @@
 
     public void testAllCharacterDevicesAreSecure() throws Exception {
         Set<File> insecure = getAllInsecureDevicesInDirAndSubdir(new File("/dev"), FileUtils.S_IFCHR);
+        Set<File> insecurePts = getAllInsecureDevicesInDirAndSubdir(new File("/dev/pts"), FileUtils.S_IFCHR);
         insecure.removeAll(CHAR_DEV_EXCEPTIONS);
+        insecure.removeAll(insecurePts);
         assertTrue("Found insecure character devices: " + insecure.toString(),
                 insecure.isEmpty());
     }
diff --git a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
index a0e03f5..91c0bf6 100644
--- a/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/BaseKeyListenerTest.java
@@ -16,132 +16,127 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.Selection;
+import android.text.Spannable;
 import android.text.method.BaseKeyListener;
+import android.text.method.cts.KeyListenerTestCase;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
-import android.view.View;
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
 
 /**
- * Test the main functionalities of the BaseKeyListener.
+ * Test {@link android.text.method.BaseKeyListener}.
  */
-public class BaseKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
+public class BaseKeyListenerTest extends KeyListenerTestCase {
     private static final CharSequence TEST_STRING = "123456";
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public BaseKeyListenerTest(){
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return mTextView.hasWindowFocus();
-            }
-        }.run();
-    }
 
     public void testBackspace() {
         final Editable content = Editable.Factory.getInstance().newEditable(TEST_STRING);
-        setTextViewText(content);
+        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
 
         // Nothing to delete when the cursor is at the beginning.
-        final MockBaseKeyListener baseKeyListener = new MockBaseKeyListener();
-        KeyEvent delKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
-        Selection.setSelection(content, 0, 0);
-        baseKeyListener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
+        final KeyEvent delKeyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL);
+        prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
+        mockBaseKeyListener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
         assertEquals("123456", content.toString());
 
         // Delete the first three letters using a selection.
-        setTextViewText(content);
-        Selection.setSelection(content, 0, 3);
-        baseKeyListener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
+        prepTextViewSync(content, mockBaseKeyListener, false, 0, 3);
+        mockBaseKeyListener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, delKeyEvent);
         assertEquals("456", content.toString());
 
-        // Delete the entire line wit ALT + DEL
-        setTextViewText(content);
-        KeyEvent altDelKeyEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL,
-                0, KeyEvent.META_ALT_ON);
-        Selection.setSelection(content, 0, 0);
-        baseKeyListener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, altDelKeyEvent);
+        // Delete the entire line with ALT + DEL
+        final KeyEvent altDelKeyEvent = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+                KeyEvent.KEYCODE_DEL, 0, KeyEvent.META_ALT_ON);
+        prepTextViewSync(content, mockBaseKeyListener, false, 0, 0);
+        mockBaseKeyListener.backspace(mTextView, content, KeyEvent.KEYCODE_DEL, altDelKeyEvent);
         assertEquals("", content.toString());
     }
 
-    private void setTextViewText(final CharSequence content) {
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(content, BufferType.EDITABLE);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-    }
-
     public void testBackspace_withSendKeys() {
-        final MockBaseKeyListener baseKeyListener = new MockBaseKeyListener();
-        final String str = "123456";
+        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
 
         // Delete the first character '1'
-        prepareTextView(str, baseKeyListener, 1, 1);
+        prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 1, 1);
         sendKeys(KeyEvent.KEYCODE_DEL);
         assertEquals("23456", mTextView.getText().toString());
 
         // Delete character '2' and '3'
-        prepareTextView(str, baseKeyListener, 1, 3);
+        prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 1, 3);
         sendKeys(KeyEvent.KEYCODE_DEL);
         assertEquals("1456", mTextView.getText().toString());
 
         // Delete everything on the line the cursor is on.
-        prepareTextView(str, baseKeyListener, 0, 0);
+        prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 0, 0);
         sendAltDelete();
         assertEquals("", mTextView.getText().toString());
 
         // ALT+DEL deletes the selection only.
-        prepareTextView(str, baseKeyListener, 2, 4);
+        prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 2, 4);
         sendAltDelete();
         assertEquals("1256", mTextView.getText().toString());
 
         // DEL key does not take effect when TextView does not have BaseKeyListener.
-        prepareTextView(str, null, 1, 1);
+        prepTextViewSync(TEST_STRING, null, true, 1, 1);
         sendKeys(KeyEvent.KEYCODE_DEL);
-        assertEquals(str, mTextView.getText().toString());
+        assertEquals(TEST_STRING, mTextView.getText().toString());
     }
 
-    private void prepareTextView(final CharSequence content, final BaseKeyListener keyListener,
-            final int selectionStart, final int selectionEnd) {
+    /*
+     * Check point:
+     * 1. Press 0 key, the content of TextView does not changed.
+     * 2. Set a selection and press DEL key, the selection is deleted.
+     * 3. ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting the event's text into the content.
+     */
+    public void testPressKey() {
+        final MockBaseKeyListener mockBaseKeyListener = new MockBaseKeyListener();
+
+        // press '0' key.
+        prepTextViewSync(TEST_STRING, mockBaseKeyListener, true, 0, 0);
+        sendKeys(KeyEvent.KEYCODE_0);
+        assertEquals("123456", mTextView.getText().toString());
+
+        // delete character '2'
+        prepTextViewSync(mTextView.getText(), mockBaseKeyListener, true, 1, 2);
+        sendKeys(KeyEvent.KEYCODE_DEL);
+        assertEquals("13456", mTextView.getText().toString());
+
+        // test ACTION_MULTIPLE KEYCODE_UNKNOWN key event.
+        KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(), "abcd",
+                KeyCharacterMap.BUILT_IN_KEYBOARD, 0);
+        prepTextViewSync(mTextView.getText(), mockBaseKeyListener, true, 2, 2);
+        mInstrumentation.sendKeySync(event);
+        mInstrumentation.waitForIdleSync();
+        // the text of TextView is never changed, onKeyOther never works.
+//        assertEquals("13abcd456", mTextView.getText().toString());
+    }
+
+    /**
+     * Prepares mTextView state for tests by synchronously setting the content and key listener, on
+     * the UI thread.
+     */
+    private void prepTextViewSync(final CharSequence content, final BaseKeyListener keyListener,
+            final boolean selectInTextView, final int selectionStart, final int selectionEnd) {
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 mTextView.setText(content, BufferType.EDITABLE);
                 mTextView.setKeyListener(keyListener);
-                mTextView.requestFocus();
-                Selection.setSelection((Editable) mTextView.getText(), selectionStart,
-                        selectionEnd);
+                Selection.setSelection(
+                        (Spannable) (selectInTextView ? mTextView.getText() : content),
+                        selectionStart, selectionEnd);
             }
         });
         mInstrumentation.waitForIdleSync();
+        assertTrue(mTextView.hasWindowFocus());
     }
 
+    /**
+     * Sends alt-delete key combo via {@link #sendKeys(int... keys)}.
+     */
     private void sendAltDelete() {
         mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ALT_LEFT));
         sendKeys(KeyEvent.KEYCODE_DEL);
@@ -149,54 +144,8 @@
     }
 
     /**
-     * Check point:
-     * 1. Press 0 key, the content of TextView does not changed.
-     * 2. Set a selection and press DEL key, the selection is deleted.
-     * 3. ACTION_MULTIPLE KEYCODE_UNKNOWN by inserting the event's text into the content.
+     * A mocked {@link android.text.method.BaseKeyListener} for testing purposes.
      */
-    public void testPressKey() {
-        final CharSequence str = "123456";
-        final MockBaseKeyListener baseKeyListener = new MockBaseKeyListener();
-
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setText(str, BufferType.EDITABLE);
-                mTextView.setKeyListener(baseKeyListener);
-                mTextView.requestFocus();
-                Selection.setSelection((Editable) mTextView.getText(), 0, 0);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        assertEquals("123456", mTextView.getText().toString());
-        // press '0' key.
-        sendKeys(KeyEvent.KEYCODE_0);
-        assertEquals("123456", mTextView.getText().toString());
-
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                Selection.setSelection((Editable) mTextView.getText(), 1, 2);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        // delete character '2'
-        sendKeys(KeyEvent.KEYCODE_DEL);
-        assertEquals("13456", mTextView.getText().toString());
-
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                Selection.setSelection((Editable) mTextView.getText(), 2, 2);
-            }
-        });
-        mInstrumentation.waitForIdleSync();
-        // test ACTION_MULTIPLE KEYCODE_UNKNOWN key event.
-        KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(), "abcd",
-                KeyCharacterMap.BUILT_IN_KEYBOARD, 0);
-        mInstrumentation.sendKeySync(event);
-        mInstrumentation.waitForIdleSync();
-        // the text of TextView is never changed, onKeyOther never works.
-//        assertEquals("13abcd456", mTextView.getText().toString());
-    }
-
     private class MockBaseKeyListener extends BaseKeyListener {
         public int getInputType() {
             return InputType.TYPE_CLASS_DATETIME
diff --git a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
index 6551b52..067a62e 100644
--- a/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateKeyListenerTest.java
@@ -16,46 +16,16 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.InputType;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.DateKeyListener;
 import android.view.KeyEvent;
 import android.widget.TextView;
 
 /**
- * Test {@link DateKeyListener}.
+ * Test {@link android.text.method.DateKeyListener}.
  */
-public class DateKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public DateKeyListenerTest(){
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return mTextView.hasWindowFocus();
-            }
-        }.run();
-    }
-
+public class DateKeyListenerTest extends KeyListenerTestCase {
     public void testConstructor() {
         new DateKeyListener();
     }
@@ -70,21 +40,20 @@
     }
 
     public void testGetAcceptedChars() {
-        MyDataKeyListener dataKeyListener = new MyDataKeyListener();
+        MockDateKeyListener mockDateKeyListener = new MockDateKeyListener();
 
         TextMethodUtils.assertEquals(DateKeyListener.CHARACTERS,
-                dataKeyListener.getAcceptedChars());
+                mockDateKeyListener.getAcceptedChars());
     }
 
     public void testGetInputType() {
-        MyDataKeyListener dataKeyListener = new MyDataKeyListener();
+        DateKeyListener dateKeyListener = new DateKeyListener();
 
-        int expected = InputType.TYPE_CLASS_DATETIME
-                | InputType.TYPE_DATETIME_VARIATION_DATE;
-        assertEquals(expected, dataKeyListener.getInputType());
+        int expected = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
+        assertEquals(expected, dateKeyListener.getInputType());
     }
 
-    /**
+    /*
      * Scenario description:
      * 1. Press '1' key and check if the content of TextView becomes "1"
      * 2. Press '2' key and check if the content of TextView becomes "12"
@@ -96,13 +65,7 @@
     public void testDateTimeKeyListener() {
         final DateKeyListener dateKeyListener = DateKeyListener.getInstance();
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(dateKeyListener);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(dateKeyListener);
         assertEquals("", mTextView.getText().toString());
 
         // press '1' key.
@@ -129,13 +92,7 @@
         assertEquals("12-/", mTextView.getText().toString());
 
         // remove DateKeyListener
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(null);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(null);
         assertEquals("12-/", mTextView.getText().toString());
 
         // press '/' key, it will not be accepted.
@@ -143,7 +100,13 @@
         assertEquals("12-/", mTextView.getText().toString());
     }
 
-    private class MyDataKeyListener extends DateKeyListener {
+    /**
+     * A mocked {@link android.text.method.DateKeyListener} for testing purposes.
+     *
+     * Allows {@link DateKeyListenerTest} to call
+     * {@link android.text.method.DateKeyListener#getAcceptedChars()}.
+     */
+    private class MockDateKeyListener extends DateKeyListener {
         @Override
         protected char[] getAcceptedChars() {
             return super.getAcceptedChars();
diff --git a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
index 9aac08b..03683dc 100644
--- a/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DateTimeKeyListenerTest.java
@@ -16,47 +16,16 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.InputType;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.DateTimeKeyListener;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
-import android.widget.TextView;
 
 /**
- * Test {@link DateTimeKeyListener}.
+ * Test {@link android.DateTimeKeyListener}.
  */
-public class DateTimeKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public DateTimeKeyListenerTest(){
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        new PollingCheck() {
-            @Override
-            protected boolean check() {
-                return mActivity.hasWindowFocus();
-            }
-        }.run();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-    }
-
+public class DateTimeKeyListenerTest extends KeyListenerTestCase {
     public void testConstructor() {
         new DateTimeKeyListener();
     }
@@ -71,10 +40,10 @@
     }
 
     public void testGetAcceptedChars() {
-        MyDateTimeKeyListener dataTimeKeyListener = new MyDateTimeKeyListener();
+        MockDateTimeKeyListener mockDateTimeKeyListener = new MockDateTimeKeyListener();
 
         TextMethodUtils.assertEquals(DateTimeKeyListener.CHARACTERS,
-                dataTimeKeyListener.getAcceptedChars());
+                mockDateTimeKeyListener.getAcceptedChars());
     }
 
     public void testGetInputType() {
@@ -85,7 +54,7 @@
         assertEquals(expected, listener.getInputType());
     }
 
-    /**
+    /*
      * Scenario description:
      * 1. Press '1' key and check if the content of TextView becomes "1"
      * 2. Press '2' key and check if the content of TextView becomes "12"
@@ -97,15 +66,8 @@
      */
     public void testDateTimeKeyListener() {
         final DateTimeKeyListener dateTimeKeyListener = DateTimeKeyListener.getInstance();
+        setKeyListenerSync(dateTimeKeyListener);
         String expectedText = "";
-
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(dateTimeKeyListener);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
         assertEquals(expectedText, mTextView.getText().toString());
 
         // press '1' key.
@@ -148,20 +110,21 @@
         }
 
         // remove DateTimeKeyListener
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(null);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(null);
         assertEquals(expectedText, mTextView.getText().toString());
 
         mInstrumentation.sendStringSync("1");
         assertEquals(expectedText, mTextView.getText().toString());
     }
 
-    private class MyDateTimeKeyListener extends DateTimeKeyListener {
+
+    /**
+     * A mocked {@link android.text.method.DateTimeKeyListener} for testing purposes.
+     *
+     * Allows {@link DateTimeKeyListenerTest} to call
+     * {@link android.text.method.DateTimeKeyListener#getAcceptedChars()}.
+     */
+    private class MockDateTimeKeyListener extends DateTimeKeyListener {
         @Override
         protected char[] getAcceptedChars() {
             return super.getAcceptedChars();
diff --git a/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
index a02bdfe..9456c7e 100644
--- a/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DialerKeyListenerTest.java
@@ -16,17 +16,17 @@
 
 package android.text.method.cts;
 
-import junit.framework.TestCase;
 import android.text.InputType;
 import android.text.Spannable;
 import android.text.SpannableString;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.DialerKeyListener;
 import android.view.KeyEvent;
 
 /**
- * Test {@link DialerKeyListener}.
+ * Test {@link android.text.method.DialerKeyListener}.
  */
-public class DialerKeyListenerTest extends TestCase {
+public class DialerKeyListenerTest extends KeyListenerTestCase {
     public void testConstructor() {
         new DialerKeyListener();
     }
@@ -76,11 +76,20 @@
         assertEquals(InputType.TYPE_CLASS_PHONE, listener.getInputType());
     }
 
+    /**
+     * A mocked {@link android.text.method.DialerKeyListener} for testing purposes.
+     *
+     * Allows {@link DialerKeyListenerTest} to call
+     * {@link android.text.method.DialerKeyListener#getAcceptedChars()} and
+     * {@link android.text.method.DialerKeyListener#lookup(KeyEvent, Spannable)}.
+     */
     private class MockDialerKeyListener extends DialerKeyListener {
+        @Override
         protected char[] getAcceptedChars() {
             return super.getAcceptedChars();
         }
 
+        @Override
         protected int lookup(KeyEvent event, Spannable content) {
             return super.lookup(event, content);
         }
diff --git a/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
index 16d9364..33a23e3 100644
--- a/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/DigitsKeyListenerTest.java
@@ -16,56 +16,25 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.InputType;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.Spanned;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.DigitsKeyListener;
 import android.view.KeyEvent;
-import android.widget.TextView;
 
 /**
  * Test {@link DigitsKeyListener}.
  */
-public class DigitsKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public DigitsKeyListenerTest(){
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return mTextView.hasWindowFocus();
-            }
-        }.run();
-    }
-
+public class DigitsKeyListenerTest extends KeyListenerTestCase {
     public void testConstructor() {
         new DigitsKeyListener();
 
         new DigitsKeyListener(true, true);
     }
 
-    /**
+    /*
      * Check point:
      * Current accepted characters are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'.
      * 1. filter "123456", return null.
@@ -114,7 +83,7 @@
         assertEquals(destString, dest.toString());
     }
 
-    /**
+    /*
      * Check point:
      * Current accepted characters are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '+'.
      * 1. filter "-123456", return null
@@ -217,7 +186,7 @@
         assertEquals(startSign, dest.toString());
     }
 
-    /**
+    /*
      * Check point:
      * Current accepted characters are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.'.
      * 1. filter "123.456", return null
@@ -287,7 +256,7 @@
         assertEquals(startDecimal, dest.toString());
     }
 
-    /**
+    /*
      * Check point:
      * Current accepted characters are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-',
      * '+'.
@@ -410,7 +379,7 @@
         assertEquals(startSign, dest.toString());
     }
 
-    /**
+    /*
      * Scenario description:
      * Current accepted characters are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'.
      *  1. Press '-' key and this key could not be accepted.
@@ -421,13 +390,7 @@
     public void testDigitsKeyListener1() {
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance();
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(digitsKeyListener);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(digitsKeyListener);
         assertEquals("", mTextView.getText().toString());
 
         // press '-' key.
@@ -447,7 +410,7 @@
         assertEquals("12", mTextView.getText().toString());
     }
 
-    /**
+    /*
      * Scenario description:
      * Current accepted characters are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '+'.
      *  1. Press '-' key and check if the content of TextView becomes "-"
@@ -461,13 +424,7 @@
     public void testDigitsKeyListener2() {
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(true, false);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(digitsKeyListener);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(digitsKeyListener);
         assertEquals("", mTextView.getText().toString());
 
         // press '-' key.
@@ -495,7 +452,7 @@
         assertEquals("-12", mTextView.getText().toString());
     }
 
-    /**
+    /*
      * Scenario description:
      * Current accepted characters are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.'.
      *  1. Press '-' key and check if the content of TextView becomes ""
@@ -509,13 +466,7 @@
     public void testDigitsKeyListener3() {
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(false, true);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(digitsKeyListener);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(digitsKeyListener);
         assertEquals("", mTextView.getText().toString());
 
         // press '-' key.
@@ -543,7 +494,7 @@
         assertEquals("1.2", mTextView.getText().toString());
     }
 
-    /**
+    /*
      * Scenario description:
      * Current accepted characters are '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '+',
      * '.'.
@@ -559,13 +510,7 @@
     public void testDigitsKeyListener4() {
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(true, true);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(digitsKeyListener);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(digitsKeyListener);
         assertEquals("", mTextView.getText().toString());
 
         // press '+' key.
@@ -593,7 +538,7 @@
         assertEquals("+1.2", mTextView.getText().toString());
     }
 
-    /**
+    /*
      * Scenario description:
      * Current accepted characters are '5', '6', '7', '8', '9'.
      *  1. Press '1' key and this key could not be accepted.
@@ -606,13 +551,7 @@
         final String accepted = "56789";
         final DigitsKeyListener digitsKeyListener = DigitsKeyListener.getInstance(accepted);
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(digitsKeyListener);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(digitsKeyListener);
         assertEquals("", mTextView.getText().toString());
 
         // press '1' key.
@@ -680,7 +619,7 @@
     }
 
     public void testGetAcceptedChars() {
-        MyDigitsKeyListener digitsKeyListener = new MyDigitsKeyListener();
+        MockDigitsKeyListener mockDigitsKeyListener = new MockDigitsKeyListener();
 
         final char[][] expected = new char[][] {
             new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' },
@@ -689,20 +628,16 @@
             new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '+', '.' },
         };
 
-        TextMethodUtils.assertEquals(expected[0],
-                digitsKeyListener.getAcceptedChars());
+        TextMethodUtils.assertEquals(expected[0], mockDigitsKeyListener.getAcceptedChars());
 
-        digitsKeyListener = new MyDigitsKeyListener(true, false);
-        TextMethodUtils.assertEquals(expected[1],
-                digitsKeyListener.getAcceptedChars());
+        mockDigitsKeyListener = new MockDigitsKeyListener(true, false);
+        TextMethodUtils.assertEquals(expected[1], mockDigitsKeyListener.getAcceptedChars());
 
-        digitsKeyListener = new MyDigitsKeyListener(false, true);
-        TextMethodUtils.assertEquals(expected[2],
-                digitsKeyListener.getAcceptedChars());
+        mockDigitsKeyListener = new MockDigitsKeyListener(false, true);
+        TextMethodUtils.assertEquals(expected[2], mockDigitsKeyListener.getAcceptedChars());
 
-        digitsKeyListener = new MyDigitsKeyListener(true, true);
-        TextMethodUtils.assertEquals(expected[3],
-                digitsKeyListener.getAcceptedChars());
+        mockDigitsKeyListener = new MockDigitsKeyListener(true, true);
+        TextMethodUtils.assertEquals(expected[3], mockDigitsKeyListener.getAcceptedChars());
     }
 
     public void testGetInputType() {
@@ -727,12 +662,18 @@
         assertEquals(expected, digitsKeyListener.getInputType());
     }
 
-    private class MyDigitsKeyListener extends DigitsKeyListener {
-        public MyDigitsKeyListener() {
+    /**
+     * A mocked {@link android.text.method.DigitsKeyListener} for testing purposes.
+     *
+     * Allows {@link DigitsKeyListenerTest} to call
+     * {@link android.text.method.DigitsKeyListener#getAcceptedChars()}.
+     */
+    private class MockDigitsKeyListener extends DigitsKeyListener {
+        public MockDigitsKeyListener() {
             super();
         }
 
-        public MyDigitsKeyListener(boolean sign, boolean decimal) {
+        public MockDigitsKeyListener(boolean sign, boolean decimal) {
             super(sign, decimal);
         }
 
diff --git a/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
new file mode 100644
index 0000000..4007f33
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/KeyListenerTestCase.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 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.text.method.cts;
+
+import com.android.cts.stub.R;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.text.format.DateUtils;
+import android.text.method.cts.KeyListenerStubActivity;
+import android.text.method.KeyListener;
+import android.widget.TextView;
+
+/**
+ * Base class for various KeyListener tests.
+ * {@link BaseKeyListenerTest}
+ * {@link DateKeyListenerTest}
+ * {@link DateTimeKeyListenerTest}
+ * {@link DigitsKeyListenerTest}
+ * {@link MultiTapKeyListenerTest}
+ * {@link NumberKeyListenerTest}
+ * {@link QwertyKeyListenerTest}
+ * {@link TextKeyKeyListenerTest}
+ *
+ * @see BaseKeyListenerTest
+ * @see DateKeyListenerTest
+ * @see DateTimeKeyListenerTest
+ * @see DigitsKeyListenerTest
+ * @see MultiTapKeyListenerTest
+ * @see NumberKeyListenerTest
+ * @see QwertyKeyListenerTest
+ * @see TextKeyKeyListenerTest
+ */
+public abstract class KeyListenerTestCase extends
+        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
+    protected KeyListenerStubActivity mActivity;
+    protected Instrumentation mInstrumentation;
+    protected TextView mTextView;
+
+    public KeyListenerTestCase() {
+        super("com.android.cts.stub", KeyListenerStubActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mInstrumentation = getInstrumentation();
+        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
+
+        assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
+    }
+
+    /**
+     * Synchronously sets mTextView's key listener on the UI thread.
+     */
+    protected void setKeyListenerSync(final KeyListener keyListener) {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView.setKeyListener(keyListener);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/tests/tests/text/src/android/text/method/cts/MetaKeyKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/MetaKeyKeyListenerTest.java
index b4a18b2..c6eb78c 100644
--- a/tests/tests/text/src/android/text/method/cts/MetaKeyKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/MetaKeyKeyListenerTest.java
@@ -16,12 +16,11 @@
 
 package android.text.method.cts;
 
-
-import android.test.AndroidTestCase;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.Spanned;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.DateKeyListener;
 import android.text.method.MetaKeyKeyListener;
 import android.view.KeyCharacterMap;
@@ -32,11 +31,11 @@
 /**
  * Test {@link MetaKeyKeyListener}.
  */
-public class MetaKeyKeyListenerTest extends AndroidTestCase {
+public class MetaKeyKeyListenerTest extends KeyListenerTestCase {
     public void testPressKey() {
         final CharSequence str = "123456";
         final MetaKeyKeyListener numberKeyListener = new DateKeyListener();
-        final View view = new ImageView(getContext());
+        final View view = new ImageView(mInstrumentation.getTargetContext());
         final Editable content = Editable.Factory.getInstance().newEditable(str);
 
         content.setSpan(Selection.SELECTION_START, 0, 0, Spanned.SPAN_POINT_POINT);
@@ -61,7 +60,7 @@
     public void testReleaseKey() {
         final CharSequence str = "123456";
         final MetaKeyKeyListener numberKeyListener = new DateKeyListener();
-        final View view = new ImageView(getContext());
+        final View view = new ImageView(mInstrumentation.getTargetContext());
         final Editable content = Editable.Factory.getInstance().newEditable(str);
 
         content.setSpan(Selection.SELECTION_START, 0, 0, Spanned.SPAN_POINT_POINT);
@@ -343,12 +342,21 @@
         assertEquals(0, state);
     }
 
+    /**
+     * A mocked {@link android.text.method.MetaKeyKeyListener} for testing purposes.
+     *
+     * Allows {@link MetaKeyKeyListenerTest} to call
+     * {@link android.text.method.MetaKeyKeyListener.resetLockedMeta(Spannable)}.
+     */
     private class MockMetaKeyKeyListener extends MetaKeyKeyListener {
         public void callResetLockedMeta(Spannable content) {
             MetaKeyKeyListener.resetLockedMeta(content);
         }
     }
 
+    /**
+     * A mocked {@link android.text.Spannable} for testing purposes.
+     */
     private class MockSpannable implements Spannable {
         private int mFlags;
         private boolean mCalledRemoveSpan = false;
diff --git a/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java
index 3b4b259..e537b24 100644
--- a/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/MultiTapKeyListenerTest.java
@@ -16,16 +16,11 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.MultiTapKeyListener;
 import android.text.method.TextKeyListener.Capitalize;
 import android.view.KeyEvent;
@@ -34,27 +29,11 @@
 
 import java.util.concurrent.TimeUnit;
 
-public class MultiTapKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
+public class MultiTapKeyListenerTest extends KeyListenerTestCase {
     /**
      * time out of MultiTapKeyListener. longer than 2000ms in case the system is sluggish.
      */
     private static final long TIME_OUT = 3000;
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public MultiTapKeyListenerTest() {
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-    }
 
     public void testConstructor() {
         new MultiTapKeyListener(Capitalize.NONE, true);
@@ -65,20 +44,20 @@
     }
 
     public void testOnSpanAdded() {
-        final MockMultiTapKeyListener multiTapKeyListener
+        final MockMultiTapKeyListener mockMultiTapKeyListener
                 = new MockMultiTapKeyListener(Capitalize.CHARACTERS, true);
         final Spannable text = new SpannableStringBuilder("123456");
 
-        assertFalse(multiTapKeyListener.hadAddedSpan());
+        assertFalse(mockMultiTapKeyListener.hadAddedSpan());
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
-                mTextView.setKeyListener(multiTapKeyListener);
+                mTextView.setKeyListener(mockMultiTapKeyListener);
                 mTextView.setText(text, BufferType.EDITABLE);
             }
         });
         mInstrumentation.waitForIdleSync();
 
-        assertTrue(multiTapKeyListener.hadAddedSpan());
+        assertTrue(mockMultiTapKeyListener.hadAddedSpan());
     }
 
     public void testOnSpanChanged() {
@@ -263,6 +242,11 @@
         assertEquals(expected, listener.getInputType());
     }
 
+    /**
+     * A mocked {@link android.text.method.MultiTapKeyListener} for testing purposes.
+     *
+     * Tracks whether {@link MockMultiTapKeyListener#onSpanAdded()} has been called.
+     */
     private class MockMultiTapKeyListener extends MultiTapKeyListener {
         private boolean mHadAddedSpan;
 
diff --git a/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
index 795382c..fa0db0d 100644
--- a/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/NumberKeyListenerTest.java
@@ -16,18 +16,12 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.Spanned;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.NumberKeyListener;
 import android.view.KeyEvent;
 import android.view.View;
@@ -35,31 +29,8 @@
 import android.widget.TextView.BufferType;
 
 
-public class NumberKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
-
-    private MockNumberKeyListener mNumberKeyListener;
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public NumberKeyListenerTest(){
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return mTextView.hasWindowFocus();
-            }
-        }.run();
-    }
+public class NumberKeyListenerTest extends KeyListenerTestCase {
+    private MockNumberKeyListener mMockNumberKeyListener;
 
     /**
      * Check point:
@@ -70,29 +41,31 @@
      * 5. Filter Spanned("12345 Android"), return Spanned("12345") and copy spans.
      */
     public void testFilter() {
-        mNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
+        mMockNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
         String source = "Android test";
         SpannableString dest = new SpannableString("012345");
-        assertEquals("", mNumberKeyListener.filter(source, 0, source.length(),
+        assertEquals("", mMockNumberKeyListener.filter(source, 0, source.length(),
                 dest, 0, dest.length()).toString());
 
         source = "12345";
         dest = new SpannableString("012345");
-        assertNull(mNumberKeyListener.filter(source, 0, source.length(), dest, 0, dest.length()));
+        assertNull(mMockNumberKeyListener.filter(source, 0, source.length(), dest, 0,
+                dest.length()));
 
         source = "";
         dest = new SpannableString("012345");
-        assertNull(mNumberKeyListener.filter(source, 0, source.length(), dest, 0, dest.length()));
+        assertNull(mMockNumberKeyListener.filter(source, 0, source.length(), dest, 0,
+                dest.length()));
 
         source = "12345 Android";
         dest = new SpannableString("012345 Android-test");
-        assertEquals("12345", mNumberKeyListener.filter(source, 0, source.length(),
+        assertEquals("12345", mMockNumberKeyListener.filter(source, 0, source.length(),
                 dest, 0, dest.length()).toString());
 
         Object what = new Object();
         Spannable spannableSource = new SpannableString("12345 Android");
         spannableSource.setSpan(what, 0, spannableSource.length(), Spanned.SPAN_POINT_POINT);
-        Spanned filtered = (Spanned) mNumberKeyListener.filter(spannableSource,
+        Spanned filtered = (Spanned) mMockNumberKeyListener.filter(spannableSource,
                 0, spannableSource.length(), dest, 0, dest.length());
         assertEquals("12345", filtered.toString());
         assertEquals(Spanned.SPAN_POINT_POINT, filtered.getSpanFlags(what));
@@ -100,7 +73,7 @@
         assertEquals("12345".length(), filtered.getSpanEnd(what));
 
         try {
-            mNumberKeyListener.filter(null, 0, 1, dest, 0, dest.length());
+            mMockNumberKeyListener.filter(null, 0, 1, dest, 0, dest.length());
             fail("should throw NullPointerException.");
         } catch (NullPointerException e) {
         }
@@ -112,18 +85,18 @@
      * key event, return the char; otherwise return '\0'.
      */
     public void testLookup() {
-        mNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
+        mMockNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
         KeyEvent event1 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_0);
         SpannableString str = new SpannableString("012345");
-        assertEquals('0', mNumberKeyListener.lookup(event1, str));
+        assertEquals('0', mMockNumberKeyListener.lookup(event1, str));
 
-        mNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.NOTHING);
+        mMockNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.NOTHING);
         KeyEvent event2 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A);
         str = new SpannableString("ABCD");
-        assertEquals('\0', mNumberKeyListener.lookup(event2, str));
+        assertEquals('\0', mMockNumberKeyListener.lookup(event2, str));
 
         try {
-            mNumberKeyListener.lookup(null, str);
+            mMockNumberKeyListener.lookup(null, str);
             fail("should throw NullPointerException.");
         } catch (NullPointerException e) {
             // expected.
@@ -131,13 +104,13 @@
     }
 
     public void testOk() {
-        mNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
+        mMockNumberKeyListener = new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
 
-        assertTrue(mNumberKeyListener.callOk(mNumberKeyListener.getAcceptedChars(), '3'));
-        assertFalse(mNumberKeyListener.callOk(mNumberKeyListener.getAcceptedChars(), 'e'));
+        assertTrue(mMockNumberKeyListener.callOk(mMockNumberKeyListener.getAcceptedChars(), '3'));
+        assertFalse(mMockNumberKeyListener.callOk(mMockNumberKeyListener.getAcceptedChars(), 'e'));
 
         try {
-            mNumberKeyListener.callOk(null, 'm');
+            mMockNumberKeyListener.callOk(null, 'm');
             fail("should throw NullPointerException.");
         } catch (NullPointerException e) {
         }
@@ -151,13 +124,13 @@
      */
     public void testPressKey() {
         final CharSequence text = "123456";
-        final MockNumberKeyListener numberKeyListener =
+        final MockNumberKeyListener mockNumberKeyListener =
             new MockNumberKeyListener(MockNumberKeyListener.DIGITS);
 
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 mTextView.setText(text, BufferType.EDITABLE);
-                mTextView.setKeyListener(numberKeyListener);
+                mTextView.setKeyListener(mockNumberKeyListener);
                 mTextView.requestFocus();
                 Selection.setSelection((Editable) mTextView.getText(), 0, 0);
             }
@@ -188,8 +161,15 @@
         assertEquals("0123456", mTextView.getText().toString());
     }
 
+    /**
+     * A mocked {@link android.text.method.NumberKeyListener} for testing purposes.
+     *
+     * Allows {@link NumberKeyListenerTest} to call
+     * {@link android.text.method.NumberKeyListener#getAcceptedChars()},
+     * {@link android.text.method.NumberKeyListener#lookup(KeyEvent, Spannable)}, and
+     * {@link android.text.method.NumberKeyListener@ok(char[], char)}.
+     */
     private static class MockNumberKeyListener extends NumberKeyListener {
-
         static final char[] DIGITS =
                 new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
 
diff --git a/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
index c97edd9..b66e19a 100644
--- a/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/QwertyKeyListenerTest.java
@@ -16,16 +16,11 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.QwertyKeyListener;
 import android.text.method.TextKeyListener;
 import android.text.method.TextKeyListener.Capitalize;
@@ -33,24 +28,7 @@
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
 
-public class QwertyKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public QwertyKeyListenerTest() {
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-    }
-
+public class QwertyKeyListenerTest extends KeyListenerTestCase {
     public void testConstructor() {
         new QwertyKeyListener(Capitalize.NONE, false);
 
diff --git a/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
index 9984efe..3e09a60 100644
--- a/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TextKeyListenerTest.java
@@ -16,19 +16,14 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
 import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.text.Editable;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.TextKeyListener;
 import android.text.method.TextKeyListener.Capitalize;
 import android.view.KeyCharacterMap;
@@ -37,33 +32,11 @@
 import android.widget.TextView;
 import android.widget.TextView.BufferType;
 
-public class TextKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
+public class TextKeyListenerTest extends KeyListenerTestCase {
     /**
      * time out of MultiTapKeyListener. longer than 2000ms in case the system is sluggish.
      */
     private static final long TIME_OUT = 3000;
-    private KeyListenerStubActivity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public TextKeyListenerTest() {
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return mTextView.hasWindowFocus();
-            }
-        }.run();
-    }
 
     public void testConstructor() {
         new TextKeyListener(Capitalize.NONE, true);
@@ -104,22 +77,22 @@
     }
 
     public void testOnSpanAdded() {
-        final MockTextKeyListener textKeyListener
+        final MockTextKeyListener mockTextKeyListener
                 = new MockTextKeyListener(Capitalize.CHARACTERS, true);
         final Spannable text = new SpannableStringBuilder("123456");
 
-        assertFalse(textKeyListener.hadAddedSpan());
+        assertFalse(mockTextKeyListener.hadAddedSpan());
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
-                mTextView.setKeyListener(textKeyListener);
+                mTextView.setKeyListener(mockTextKeyListener);
                 mTextView.setText(text, BufferType.EDITABLE);
             }
         });
         mInstrumentation.waitForIdleSync();
 
-        assertTrue(textKeyListener.hadAddedSpan());
+        assertTrue(mockTextKeyListener.hadAddedSpan());
 
-        textKeyListener.release();
+        mockTextKeyListener.release();
     }
 
     public void testGetInstance1() {
@@ -243,7 +216,6 @@
         mActivity.runOnUiThread(new Runnable() {
             public void run() {
                 mTextView.setText("", BufferType.EDITABLE);
-                mTextView.requestFocus();
                 Selection.setSelection((Editable) mTextView.getText(), 0, 0);
                 mTextView.setKeyListener(textKeyListener);
             }
@@ -275,6 +247,12 @@
         listener.release();
     }
 
+    /**
+     * A mocked {@link android.text.method.TextKeyListener} for testing purposes.
+     *
+     * Tracks whether {@link MockTextKeyListener#onSpanAdded(Spannable, Object, int, int)} has been
+     * called.
+     */
     private class MockTextKeyListener extends TextKeyListener {
         private boolean mHadAddedSpan;
 
diff --git a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
index f9c172b..7d8631b 100644
--- a/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
+++ b/tests/tests/text/src/android/text/method/cts/TimeKeyListenerTest.java
@@ -16,44 +16,13 @@
 
 package android.text.method.cts;
 
-import com.android.cts.stub.R;
-
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.cts.util.PollingCheck;
-import android.test.ActivityInstrumentationTestCase2;
 import android.text.InputType;
+import android.text.method.cts.KeyListenerTestCase;
 import android.text.method.TimeKeyListener;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
-import android.widget.TextView;
 
-public class TimeKeyListenerTest extends
-        ActivityInstrumentationTestCase2<KeyListenerStubActivity> {
-    private Activity mActivity;
-    private Instrumentation mInstrumentation;
-    private TextView mTextView;
-
-    public TimeKeyListenerTest(){
-        super("com.android.cts.stub", KeyListenerStubActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mActivity = getActivity();
-        mInstrumentation = getInstrumentation();
-        mTextView = (TextView) mActivity.findViewById(R.id.keylistener_textview);
-        new PollingCheck(1000) {
-            @Override
-            protected boolean check() {
-                return mTextView.hasWindowFocus();
-            }
-        }.run();
-    }
-
+public class TimeKeyListenerTest extends KeyListenerTestCase {
     public void testConstructor() {
         new TimeKeyListener();
     }
@@ -68,9 +37,9 @@
     }
 
     public void testGetAcceptedChars() {
-        MyTimeKeyListener timeKeyListener = new MyTimeKeyListener();
+        MockTimeKeyListener mockTimeKeyListener = new MockTimeKeyListener();
         TextMethodUtils.assertEquals(TimeKeyListener.CHARACTERS,
-                timeKeyListener.getAcceptedChars());
+                mockTimeKeyListener.getAcceptedChars());
     }
 
     public void testGetInputType() {
@@ -80,7 +49,7 @@
         assertEquals(expected, listener.getInputType());
     }
 
-    /**
+    /*
      * Scenario description:
      * 1. Press '1' key and check if the content of TextView becomes "1"
      * 2. Press '2' key and check if the content of TextView becomes "12"
@@ -94,13 +63,7 @@
         final TimeKeyListener timeKeyListener = TimeKeyListener.getInstance();
         String expectedText = "";
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(timeKeyListener);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(timeKeyListener);
         assertEquals(expectedText, mTextView.getText().toString());
 
         // press '1' key.
@@ -142,20 +105,20 @@
             assertEquals(expectedText, mTextView.getText().toString());
         }
 
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mTextView.setKeyListener(null);
-                mTextView.requestFocus();
-            }
-        });
-        mInstrumentation.waitForIdleSync();
+        setKeyListenerSync(null);
 
         // press '1' key.
         mInstrumentation.sendStringSync("1");
         assertEquals(expectedText, mTextView.getText().toString());
     }
 
-    private class MyTimeKeyListener extends TimeKeyListener {
+    /**
+     * A mocked {@link android.text.method.TimeKeyListener} for testing purposes.
+     *
+     * Allows {@link TimeKeyListenerTest} to call
+     * {@link android.text.method.TimeKeyListener#getAcceptedChars()}.
+     */
+    private class MockTimeKeyListener extends TimeKeyListener {
         @Override
         protected char[] getAcceptedChars() {
             return super.getAcceptedChars();
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 9df8c1f..e833943 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -38,6 +38,7 @@
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.TouchUtils;
 import android.test.UiThreadTest;
+import android.text.format.DateUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -90,7 +91,7 @@
 
     private Resources mResources;
     private MockViewParent mMockParent;
-    private Activity mActivity;
+    private ViewTestStubActivity mActivity;
 
     /** timeout delta when wait in case the system is sluggish */
     private static final long TIMEOUT_DELTA = 10000;
@@ -109,6 +110,7 @@
         }.run();
         mResources = mActivity.getResources();
         mMockParent = new MockViewParent(mActivity);
+        assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
     }
 
     public void testConstructor() {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
index 2a5044e..5c9c958 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -34,6 +34,8 @@
     private CtsTestServer mWebServer;
     private WebIconDatabase mIconDb;
     private WebViewOnUiThread mOnUiThread;
+    private boolean mBlockWindowCreationSync;
+    private boolean mBlockWindowCreationAsync;
 
     public WebChromeClientTest() {
         super(WebViewStubActivity.class);
@@ -122,7 +124,7 @@
         }.run();
     }
 
-    public void testWindows() throws Exception {
+    public void runWindowTest(boolean expectWindowClose) throws Exception {
         final MockWebChromeClient webChromeClient = new MockWebChromeClient();
         mOnUiThread.setWebChromeClient(webChromeClient);
 
@@ -144,12 +146,30 @@
                 return webChromeClient.hadOnCreateWindow();
             }
         }.run();
-        new PollingCheck(TEST_TIMEOUT) {
-            @Override
-            protected boolean check() {
-                return webChromeClient.hadOnCloseWindow();
-            }
-        }.run();
+
+        if (expectWindowClose) {
+            new PollingCheck(TEST_TIMEOUT) {
+                @Override
+                protected boolean check() {
+                    return webChromeClient.hadOnCloseWindow();
+                }
+            }.run();
+        } else {
+            assertFalse(webChromeClient.hadOnCloseWindow());
+        }
+    }
+    public void testWindows() throws Exception {
+        runWindowTest(true);
+    }
+
+    public void testBlockWindowsSync() throws Exception {
+        mBlockWindowCreationSync = true;
+        runWindowTest(false);
+    }
+
+    public void testBlockWindowsAsync() throws Exception {
+        mBlockWindowCreationAsync = true;
+        runWindowTest(false);
     }
 
     public void testOnJsBeforeUnload() throws Exception {
@@ -380,16 +400,23 @@
         @Override
         public boolean onCreateWindow(WebView view, boolean dialog, boolean userGesture,
                 Message resultMsg) {
-            WebView childView = new WebView(getActivity());
-            final WebSettings settings = childView.getSettings();
-            settings.setJavaScriptEnabled(true);
-            childView.setWebChromeClient(this);
-            WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
-            transport.setWebView(childView);
-            resultMsg.sendToTarget();
             mHadOnCreateWindow = true;
-            getActivity().addContentView(childView, new ViewGroup.LayoutParams(
-                    ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+            if (mBlockWindowCreationSync) {
+                return false;
+            }
+            WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
+            if (mBlockWindowCreationAsync) {
+                transport.setWebView(null);
+            } else {
+                WebView childView = new WebView(getActivity());
+                final WebSettings settings = childView.getSettings();
+                settings.setJavaScriptEnabled(true);
+                childView.setWebChromeClient(this);
+                transport.setWebView(childView);
+                getActivity().addContentView(childView, new ViewGroup.LayoutParams(
+                        ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+            }
+            resultMsg.sendToTarget();
             return true;
         }
 
diff --git a/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java b/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
index 5426ae9..e583dce 100644
--- a/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HeaderViewListAdapterTest.java
@@ -81,21 +81,6 @@
         HeaderViewFullAdapter fullAdapter = new HeaderViewFullAdapter();
         headerViewListAdapter = new HeaderViewListAdapter(null, null, fullAdapter);
         assertFalse(headerViewListAdapter.isEmpty());
-
-        ListView lv = new ListView(getContext());
-        ArrayList<ListView.FixedViewInfo> header = new ArrayList<ListView.FixedViewInfo>(4);
-        header.add(lv.new FixedViewInfo());
-        headerViewListAdapter = new HeaderViewListAdapter(header, null, null);
-        assertEquals(1, headerViewListAdapter.getHeadersCount());
-        assertFalse(headerViewListAdapter.isEmpty());
-
-        lv = new ListView(getContext());
-        ArrayList<ListView.FixedViewInfo> footer = new ArrayList<ListView.FixedViewInfo>(4);
-        footer.add(lv.new FixedViewInfo());
-        headerViewListAdapter = new HeaderViewListAdapter(null, footer, null);
-        assertEquals(1, headerViewListAdapter.getFootersCount());
-        assertFalse(headerViewListAdapter.isEmpty());
-
     }
 
     public void testRemoveHeader() {
diff --git a/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java b/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
index 2afc4fa..621c8cd 100644
--- a/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
+++ b/tools/cts-java-scanner/src/com/android/cts/javascanner/DocletRunner.java
@@ -73,6 +73,7 @@
         sourcePath.add("./cts/suite/pts/deviceTests/ptsutil/src");
         sourcePath.add("./cts/libs/util/src");
         sourcePath.add("./frameworks/testing/uiautomator/library/testrunner-src");
+        sourcePath.add("./frameworks/testing/uiautomator_test_libraries/src");
         sourcePath.add(sourceDir.toString());
         return join(sourcePath, ":");
     }
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index 9517d8e..71c093b 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -134,10 +134,8 @@
             if (mReportDir == null) {
                 mReportDir = ctsBuildHelper.getResultsDir();
             }
-            // create a unique directory for saving results, using old cts host convention
-            // TODO: in future, consider using LogFileSaver to create build-specific directories
-            mReportDir = new File(mReportDir, TimeUtil.getResultTimestamp());
-            mReportDir.mkdirs();
+            mReportDir = createUniqueReportDir(mReportDir);
+
             mStartTime = getTimestamp();
             logResult("Created result dir %s", mReportDir.getName());
         }
@@ -152,6 +150,39 @@
     }
 
     /**
+     * Create a unique directory for saving results.
+     * <p/>
+     * Currently using legacy CTS host convention of timestamp directory names. In case of
+     * collisions, will use {@link FileUtil} to generate unique file name.
+     * <p/>
+     * TODO: in future, consider using LogFileSaver to create build-specific directories
+     *
+     * @param parentDir the parent folder to create dir in
+     * @return the created directory
+     */
+    private static synchronized File createUniqueReportDir(File parentDir) {
+        // TODO: in future, consider using LogFileSaver to create build-specific directories
+
+        File reportDir = new File(parentDir, TimeUtil.getResultTimestamp());
+        if (reportDir.exists()) {
+            // directory with this timestamp exists already! Choose a unique, although uglier, name
+            try {
+                reportDir = FileUtil.createTempDir(TimeUtil.getResultTimestamp() + "_", parentDir);
+            } catch (IOException e) {
+                CLog.e(e);
+                CLog.e("Failed to create result directory %s", reportDir.getAbsolutePath());
+            }
+        } else {
+            if (!reportDir.mkdirs()) {
+                // TODO: consider throwing an exception
+                CLog.e("mkdirs failed when attempting to create result directory %s",
+                        reportDir.getAbsolutePath());
+            }
+        }
+        return reportDir;
+    }
+
+    /**
      * Helper method to retrieve the {@link CtsBuildHelper}.
      * @param ctsBuild
      */