auto import from //depot/cupcake/@135843
diff --git a/tests/AndroidTests/Android.mk b/tests/AndroidTests/Android.mk
new file mode 100644
index 0000000..f5e49d7
--- /dev/null
+++ b/tests/AndroidTests/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := framework-tests android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client
+
+# Resource unit tests use a private locale
+LOCAL_AAPT_FLAGS = -c xx_YY -c cs
+
+LOCAL_SRC_FILES := \
+	$(call all-subdir-java-files) \
+	src/com/android/unit_tests/os/IAidlTest.aidl
+
+LOCAL_PACKAGE_NAME := AndroidTests
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
new file mode 100644
index 0000000..843d844
--- /dev/null
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.unit_tests"
+        android:sharedUserId="com.android.uid.test">
+    <permission android:name="com.android.unit_tests.permission.TEST_GRANTED"
+        android:protectionLevel="normal"
+            android:label="@string/permlab_testGranted"
+            android:description="@string/permdesc_testGranted">
+        <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+        <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+        <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+        <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+        <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+        <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+    </permission>
+    <permission android:name="com.android.unit_tests.permission.TEST_DENIED"
+        android:protectionLevel="normal"
+            android:label="@string/permlab_testDenied"
+            android:description="@string/permdesc_testDenied" />
+
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_SMS"/>
+    <uses-permission android:name="android.permission.WRITE_SMS"/>
+    <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
+    <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
+    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
+    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WRITE_GSERVICES" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
+
+    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
+    <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
+    <uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
+    <!-- InstrumentationTestRunner for AndroidTests -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.unit_tests"
+                     android:label="Tests for AndroidTests (unit tests collection)"/>
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+
+        <!-- Activity-level metadata -->
+        <meta-data android:name="com.android.unit_tests.isApp" android:value="true" />
+        <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+        <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+        <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+        <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+        <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+        <meta-data android:name="com.android.unit_tests.reference"
+                   android:resource="@xml/metadata_app" />
+
+        <activity android:name="AndroidPerformanceTests" android:label="Android Performance Tests">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.UNIT_TEST" />
+            </intent-filter>
+        </activity>
+
+        <!-- Application components used for activity tests -->
+
+        <activity android:name=".activity.TestedActivity"
+                android:process=":remoteActivity">
+        </activity>
+        <activity android:name=".activity.LocalActivity" android:multiprocess="true">
+            <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+            <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+            <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+            <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+            <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+            <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+        </activity>
+        <activity android:name=".activity.TestedScreen"
+                android:process=":remoteScreen">
+        </activity>
+        <activity android:name=".activity.LocalScreen" android:multiprocess="true">
+        </activity>
+        <activity android:name=".activity.ClearTop" android:multiprocess="true"
+                android:launchMode="singleTop">
+        </activity>
+        <activity android:name=".activity.LocalDialog" android:multiprocess="true"
+                android:theme="@android:style/Theme.Dialog">
+        </activity>
+        <activity android:name=".activity.SubActivityScreen">
+        </activity>
+        <activity android:name=".activity.RemoteSubActivityScreen"
+                android:process=":remoteActivity">
+        </activity>
+        <activity android:name=".activity.LaunchpadActivity" android:multiprocess="true">
+        </activity>
+        <activity android:name=".activity.LaunchpadTabActivity" android:multiprocess="true">
+        </activity>
+
+        <receiver android:name=".activity.AbortReceiver">
+            <intent-filter android:priority="1">
+                <action android:name="com.android.unit_tests.activity.BROADCAST_ABORT" />
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".activity.LocalReceiver">
+            <intent-filter android:priority="-1">
+                <action android:name="com.android.unit_tests.activity.BROADCAST_ABORT" />
+                <action android:name="com.android.unit_tests.activity.BROADCAST_ALL" />
+                <action android:name="com.android.unit_tests.activity.BROADCAST_REPEAT" />
+                <action android:name="com.android.unit_tests.activity.BROADCAST_LOCAL" />
+                <action android:name="com.android.unit_tests.activity.BROADCAST_FAIL_REGISTER" />
+                <action android:name="com.android.unit_tests.activity.BROADCAST_FAIL_BIND" />
+            </intent-filter>
+            <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+            <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+            <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+            <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+            <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+            <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+        </receiver>
+        <receiver android:name=".activity.ResultReceiver">
+            <intent-filter>
+                <action android:name="com.android.unit_tests.activity.BROADCAST_RESULT" />
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".activity.LocalGrantedReceiver"
+                android:permission="com.android.unit_tests.permission.TEST_GRANTED">
+            <intent-filter android:priority="-1">
+                <action android:name="com.android.unit_tests.activity.BROADCAST_LOCAL_GRANTED" />
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".activity.LocalDeniedReceiver"
+                android:permission="com.android.unit_tests.permission.TEST_DENIED">
+            <intent-filter android:priority="-1">
+                <action android:name="com.android.unit_tests.activity.BROADCAST_LOCAL_DENIED" />
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".activity.RemoteReceiver"
+                android:process=":remoteReceiver">
+            <intent-filter android:priority="2">
+                <action android:name="com.android.unit_tests.activity.BROADCAST_ABORT" />
+                <action android:name="com.android.unit_tests.activity.BROADCAST_ALL" />
+                <action android:name="com.android.unit_tests.activity.BROADCAST_REPEAT" />
+                <action android:name="com.android.unit_tests.activity.BROADCAST_REMOTE" />
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".activity.RemoteGrantedReceiver"
+                android:permission="com.android.unit_tests.permission.TEST_GRANTED">
+            <intent-filter android:priority="2">
+                <action android:name="com.android.unit_tests.activity.BROADCAST_REMOTE_GRANTED" />
+            </intent-filter>
+        </receiver>
+        <receiver android:name=".activity.RemoteDeniedReceiver"
+                android:permission="com.android.unit_tests.permission.TEST_DENIED">
+            <intent-filter android:priority="2">
+                <action android:name="com.android.unit_tests.activity.BROADCAST_REMOTE_DENIED" />
+            </intent-filter>
+        </receiver>
+        <service android:name=".activity.LocalService">
+            <intent-filter>
+                <action android:name="com.android.unit_tests.activity.SERVICE_LOCAL" />
+            </intent-filter>
+            <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+            <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+            <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+            <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+            <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+            <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+        </service>
+        <service android:name=".activity.LocalDeniedService"
+                android:permission="com.android.unit_tests.permission.TEST_DENIED">
+            <intent-filter>
+                <action android:name="com.android.unit_tests.activity.SERVICE_LOCAL_DENIED" />
+            </intent-filter>
+        </service>
+        <service android:name=".activity.LocalGrantedService"
+                android:permission="com.android.unit_tests.permission.TEST_GRANTED">
+            <intent-filter>
+                <action android:name="com.android.unit_tests.activity.SERVICE_LOCAL_GRANTED" />
+            </intent-filter>
+        </service>
+
+        <provider android:name=".activity.LocalProvider"
+                android:authorities="com.android.unit_tests.LocalProvider">
+            <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+            <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+            <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+            <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+            <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+            <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+        </provider>
+
+        <!-- Application components used for os tests -->
+
+        <service android:name=".os.MessengerService"
+                android:process=":messengerService">
+        </service>
+
+        <!-- Application components used for search manager tests -->
+        <!-- TODO: Removed temporarily - need to be replaced using mocks -->
+
+        <!-- Used to test IPC. -->
+        <service android:name=".binder.BinderTestService"
+                 android:process="binder.BinderTestService" />
+        <service android:name=".binder.BinderPerformanceService"
+                 android:process="binder.BinderPerformanceService" />
+        <service android:name=".binder.BinderVsMessagingService"
+                 android:process="binder.BinderVsMessagingService" />
+    </application>
+</manifest>
diff --git a/tests/AndroidTests/DisabledTestApp/Android.mk b/tests/AndroidTests/DisabledTestApp/Android.mk
new file mode 100644
index 0000000..a5daedf
--- /dev/null
+++ b/tests/AndroidTests/DisabledTestApp/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := DisabledTestApp
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml b/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..4d6843e
--- /dev/null
+++ b/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.unit_tests.disabled_app"
+        android:sharedUserId="com.android.uid.test">
+
+    <application enabled="false">
+
+        <!-- Used to test package component enabling and disabling -->
+        <activity android:name=".DisabledActivity" android:enabled="false" >
+        </activity>
+        <activity android:name=".EnabledActivity" >
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java b/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java
new file mode 100644
index 0000000..4e4dc85
--- /dev/null
+++ b/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.disabled_app;
+
+import android.app.Activity;
+
+/**
+ * Empty Activity for testing
+ */
+
+public class EnabledActivity extends Activity {
+
+}
diff --git a/tests/AndroidTests/EnabledTestApp/Android.mk b/tests/AndroidTests/EnabledTestApp/Android.mk
new file mode 100644
index 0000000..4b986d3
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := EnabledTestApp
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml b/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..ad610f1
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.unit_tests.enabled_app"
+        android:sharedUserId="com.android.uid.test">
+
+    <application>
+
+        <!-- Used to test package component enabling and disabling -->
+        <activity android:name=".DisabledActivity" android:enabled="false" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.unit_tests.enabled_app.TEST_CATEGORY" />
+            </intent-filter>
+        </activity>
+        <service android:name=".DisabledService" android:enabled="false" >
+        </service>
+        <receiver android:name=".DisabledReceiver" android:enabled="false" >
+            <intent-filter>
+                <action android:name="android.intent.action.ENABLED_APP_DISABLED_RECEIVER" />
+            </intent-filter>
+        </receiver>
+        <provider android:name=".DisabledProvider" android:enabled="false"
+                  android:authorities="com.android.unit_tests.enabled_app.DisabledProvider"
+                  android:process=":disabled.provider.process" />
+        <activity android:name=".EnabledActivity" >
+        </activity>
+        <service android:name=".EnabledService" android:enabled="true" >
+        </service>
+        <receiver android:name=".EnabledReceiver" >
+            <intent-filter>
+                <action android:name="android.intent.action.ENABLED_APP_ENABLED_RECEIVER" />
+            </intent-filter>
+        </receiver>
+        <provider android:name=".EnabledProvider"
+                  android:authorities="com.android.unit_tests.enabled_app.EnabledProvider"
+                  android:process=":enabled.provider.process" />
+    </application>
+</manifest>
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java
new file mode 100644
index 0000000..0ab0416
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.enabled_app;
+
+import android.app.Activity;
+
+/**
+ * Empty Activity for testing
+ */
+
+public class DisabledActivity extends Activity {
+
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java
new file mode 100644
index 0000000..06527f9
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.enabled_app;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * Empty ContentProvider for testing
+ */
+
+public class DisabledProvider extends ContentProvider {
+
+    public boolean onCreate() {
+        return false;
+    }
+
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+                        String sortOrder) {
+        return null;
+    }
+
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java
new file mode 100644
index 0000000..c27b87e
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.enabled_app;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Empty IntentReceiver for testing
+ */
+
+public class DisabledReceiver extends BroadcastReceiver {
+
+    public void onReceive(Context context, Intent intent) {
+
+    }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java
new file mode 100644
index 0000000..ed8d0b9
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.enabled_app;
+
+import android.app.Service;
+import android.os.IBinder;
+import android.content.Intent;
+
+/**
+ * Empty Service for testing
+ */
+
+public class DisabledService extends Service {
+
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java
new file mode 100644
index 0000000..cfac3ec
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.enabled_app;
+
+import android.app.Activity;
+
+/**
+ * Empty Activity for testing
+ */
+
+public class EnabledActivity extends Activity {
+
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java
new file mode 100644
index 0000000..764937f
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.enabled_app;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * Empty ContentProvider for testing
+ */
+
+public class EnabledProvider extends ContentProvider {
+
+    public boolean onCreate() {
+        return false;
+    }
+
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+                        String sortOrder) {
+        return null;
+    }
+
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java
new file mode 100644
index 0000000..707448f
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.enabled_app;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Empty IntentReceiver for testing
+ */
+
+public class EnabledReceiver extends BroadcastReceiver {
+
+    public void onReceive(Context context, Intent intent) {
+
+    }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java
new file mode 100644
index 0000000..81a80b3
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.enabled_app;
+
+import android.app.Service;
+import android.os.IBinder;
+import android.content.Intent;
+
+/**
+ * Empty Service for testing
+ */
+
+public class EnabledService extends Service {
+
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+}
diff --git a/tests/AndroidTests/MODULE_LICENSE_APACHE2 b/tests/AndroidTests/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/AndroidTests/MODULE_LICENSE_APACHE2
diff --git a/tests/AndroidTests/NOTICE b/tests/AndroidTests/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/tests/AndroidTests/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2008, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/tests/AndroidTests/assets/text.txt b/tests/AndroidTests/assets/text.txt
new file mode 100644
index 0000000..3d8c519
--- /dev/null
+++ b/tests/AndroidTests/assets/text.txt
@@ -0,0 +1 @@
+OneTwoThreeFourFiveSixSevenEightNineTen
\ No newline at end of file
diff --git a/tests/AndroidTests/res/drawable/test128x96.png b/tests/AndroidTests/res/drawable/test128x96.png
new file mode 100644
index 0000000..28dc925
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test128x96.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test16x12.png b/tests/AndroidTests/res/drawable/test16x12.png
new file mode 100644
index 0000000..1a3c7e5
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test16x12.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test256x192.png b/tests/AndroidTests/res/drawable/test256x192.png
new file mode 100644
index 0000000..ce8ee04
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test256x192.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test320x240.png b/tests/AndroidTests/res/drawable/test320x240.png
new file mode 100644
index 0000000..9b5800d
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test320x240.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test32x24.png b/tests/AndroidTests/res/drawable/test32x24.png
new file mode 100644
index 0000000..76bab75
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test32x24.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test64x48.png b/tests/AndroidTests/res/drawable/test64x48.png
new file mode 100644
index 0000000..9119613
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test64x48.png
Binary files differ
diff --git a/tests/AndroidTests/res/layout/layout_five.xml b/tests/AndroidTests/res/layout/layout_five.xml
new file mode 100644
index 0000000..fd1e0ef
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_five.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+	<TextView android:id="@+id/text" android:text="@string/layout_five_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/AndroidTests/res/layout/layout_four.xml b/tests/AndroidTests/res/layout/layout_four.xml
new file mode 100644
index 0000000..e5a78bcfd
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_four.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text" android:text="@string/layout_four_text_text"/>
diff --git a/tests/AndroidTests/res/layout/layout_one.xml b/tests/AndroidTests/res/layout/layout_one.xml
new file mode 100644
index 0000000..f5c78bd
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_one.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<view xmlns:android="http://schemas.android.com/apk/res/android" class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/viewOne" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
diff --git a/tests/AndroidTests/res/layout/layout_six.xml b/tests/AndroidTests/res/layout/layout_six.xml
new file mode 100644
index 0000000..6efcdf3
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_six.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+	<TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/AndroidTests/res/layout/layout_tag.xml b/tests/AndroidTests/res/layout/layout_tag.xml
new file mode 100644
index 0000000..1f17701
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_tag.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.unit_tests.InflateTest$ViewOne"
+    android:id="@+id/viewOne" android:tag="MyTag"
+    android:layout_width="fill_parent" android:layout_height="fill_parent"/>
diff --git a/tests/AndroidTests/res/layout/layout_three.xml b/tests/AndroidTests/res/layout/layout_three.xml
new file mode 100644
index 0000000..77b2aa9
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_three.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+	<view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view1" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+	<view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view2" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+	<view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view3" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+	<view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view4" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+	<view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view5" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+	<view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view6" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+</LinearLayout>
diff --git a/tests/AndroidTests/res/layout/layout_two.xml b/tests/AndroidTests/res/layout/layout_two.xml
new file mode 100644
index 0000000..9c99710
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_two.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+	<view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/viewOne" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+</LinearLayout>
+
diff --git a/tests/AndroidTests/res/raw/calendarjs.txt b/tests/AndroidTests/res/raw/calendarjs.txt
new file mode 100644
index 0000000..15f7bab
--- /dev/null
+++ b/tests/AndroidTests/res/raw/calendarjs.txt
@@ -0,0 +1 @@
+{"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns$gd":"http://schemas.google.com/g/2005","xmlns$gCal":"http://schemas.google.com/gCal/2005","id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic"},"updated":{"$t":"2007-02-06T02:55:15.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"w g"},"subtitle":{"type":"text","$t":"w g"},"link":[{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic?alt\u003Djson\u0026max-results\u003D25"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"generator":{"version":"1.0","uri":"http://www.google.com/calendar","$t":"Google Calendar"},"openSearch$totalResults":{"$t":"13"},"openSearch$startIndex":{"$t":"1"},"openSearch$itemsPerPage":{"$t":"25"},"gCal$timezone":{"value":"America/Los_Angeles"},"entry":[{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/7iqc1ro0ihc69vhsiq3uabooig"},"published":{"$t":"2007-02-05T22:04:50.000Z"},"updated":{"$t":"2007-02-05T22:04:50.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Wed Feb 7, 2007 13:30 to Wed Feb 7, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Wed Feb 7, 2007 13:30 to Wed Feb 7, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DN2lxYzFybzBpaGM2OXZoc2lxM3VhYm9vaWcgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/7iqc1ro0ihc69vhsiq3uabooig"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/kp4gil76n2vcrkt9kaotj3s12c"},"published":{"$t":"2007-02-05T22:04:42.000Z"},"updated":{"$t":"2007-02-05T22:04:42.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Fri Feb 9, 2007 15:30 to Fri Feb 9, 2007 18:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Fri Feb 9, 2007 15:30 to Fri Feb 9, 2007 18:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Da3A0Z2lsNzZuMnZjcmt0OWthb3RqM3MxMmMgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/kp4gil76n2vcrkt9kaotj3s12c"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/gkhb48fj68lcp15fd1k03tjbj0"},"published":{"$t":"2007-02-05T22:04:35.000Z"},"updated":{"$t":"2007-02-05T22:04:35.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 6"},"summary":{"type":"html","$t":"When: Sat Feb 10, 2007 14:00 to Sat Feb 10, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Sat Feb 10, 2007 14:00 to Sat Feb 10, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DZ2toYjQ4Zmo2OGxjcDE1ZmQxazAzdGpiajAgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/gkhb48fj68lcp15fd1k03tjbj0"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/32p5g68cpean3p2ol7kanj38sg"},"published":{"$t":"2007-02-05T22:04:29.000Z"},"updated":{"$t":"2007-02-05T22:04:29.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 5"},"summary":{"type":"html","$t":"When: Fri Feb 9, 2007 09:00 to 10:30\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Fri Feb 9, 2007 09:00 to 10:30\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DMzJwNWc2OGNwZWFuM3Ayb2w3a2FuajM4c2cgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/32p5g68cpean3p2ol7kanj38sg"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tfqpth26conshdmav0apje1tf4"},"published":{"$t":"2007-02-05T22:04:19.000Z"},"updated":{"$t":"2007-02-05T22:04:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Thu Feb 8, 2007 15:00 to Thu Feb 8, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Thu Feb 8, 2007 15:00 to Thu Feb 8, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DdGZxcHRoMjZjb25zaGRtYXYwYXBqZTF0ZjQgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tfqpth26conshdmav0apje1tf4"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/onbo9mhbr5m6mo356nog7uel4s"},"published":{"$t":"2007-02-05T22:04:07.000Z"},"updated":{"$t":"2007-02-05T22:04:07.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"Sharks at Anaheim"},"summary":{"type":"html","$t":"When: Wed Feb 7, 2007 19:00 to 22:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Wed Feb 7, 2007 19:00 to 22:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db25ibzltaGJyNW02bW8zNTZub2c3dWVsNHMgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/onbo9mhbr5m6mo356nog7uel4s"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tjqrd9fve576hieh3sa67nql5k"},"published":{"$t":"2007-02-05T22:04:02.000Z"},"updated":{"$t":"2007-02-05T22:04:02.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"Sharks vs. ANAHEIM"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 19:30 to 22:30\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 19:30 to 22:30\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DdGpxcmQ5ZnZlNTc2aGllaDNzYTY3bnFsNWsgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tjqrd9fve576hieh3sa67nql5k"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/or6dtpn065f9mntond4jh2docc"},"published":{"$t":"2007-02-05T22:03:52.000Z"},"updated":{"$t":"2007-02-05T22:03:52.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 14:00 to 15:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 14:00 to 15:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db3I2ZHRwbjA2NWY5bW50b25kNGpoMmRvY2Mgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/or6dtpn065f9mntond4jh2docc"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/k70v8o4jt1afi17hg2spavq1c0"},"published":{"$t":"2007-02-05T22:03:36.000Z"},"updated":{"$t":"2007-02-05T22:03:36.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"lunch"},"summary":{"type":"html","$t":"Recurring Event\u003Cbr\u003E First start: 2007-02-06 12:00:00 PST \u003Cbr\u003E Duration: 3600    \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"Recurring Event\u003Cbr\u003E First start: 2007-02-06 12:00:00 PST \u003Cbr\u003E Duration: 3600    \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DazcwdjhvNGp0MWFmaTE3aGcyc3BhdnExYzBfMjAwNzAyMDZUMjAwMDAwWiB3Z0B2b2ljZW1lLm5ldA","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/k70v8o4jt1afi17hg2spavq1c0"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/6ee7b8nohdt03tv0gknm4v7124"},"published":{"$t":"2007-02-05T22:03:19.000Z"},"updated":{"$t":"2007-02-05T22:03:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 4"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 09:00 to 11:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 09:00 to 11:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DNmVlN2I4bm9oZHQwM3R2MGdrbm00djcxMjQgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/6ee7b8nohdt03tv0gknm4v7124"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/of1vh1r2q5aqdplo65i8bqbn3o"},"published":{"$t":"2007-02-05T22:03:11.000Z"},"updated":{"$t":"2007-02-05T22:03:11.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 3"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 18:00 to 19:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 18:00 to 19:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db2YxdmgxcjJxNWFxZHBsbzY1aThicWJuM28gd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/of1vh1r2q5aqdplo65i8bqbn3o"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/s7ahgfomlgii9qbkgpfbinr9u8"},"published":{"$t":"2007-02-05T22:02:40.000Z"},"updated":{"$t":"2007-02-05T22:03:04.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 2"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 16:30 to 17:30\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 16:30 to 17:30\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DczdhaGdmb21sZ2lpOXFia2dwZmJpbnI5dTggd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/s7ahgfomlgii9qbkgpfbinr9u8"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/rl8focglfe6jndql4u8lg73q5k"},"published":{"$t":"2007-02-05T22:02:28.000Z"},"updated":{"$t":"2007-02-05T22:02:53.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 1"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 15:00 to Mon Feb 5, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 15:00 to Mon Feb 5, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E   \u003Cbr\u003EEvent Status:     confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Dcmw4Zm9jZ2xmZTZqbmRxbDR1OGxnNzNxNWsgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/rl8focglfe6jndql4u8lg73q5k"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}}]}}
\ No newline at end of file
diff --git a/tests/AndroidTests/res/raw/calendarjsgz.jsgz b/tests/AndroidTests/res/raw/calendarjsgz.jsgz
new file mode 100644
index 0000000..6f1bf54
--- /dev/null
+++ b/tests/AndroidTests/res/raw/calendarjsgz.jsgz
Binary files differ
diff --git a/tests/AndroidTests/res/raw/calendarxml.xml b/tests/AndroidTests/res/raw/calendarxml.xml
new file mode 100644
index 0000000..1adcd74
--- /dev/null
+++ b/tests/AndroidTests/res/raw/calendarxml.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:gCal='http://schemas.google.com/gCal/2005'><id>http://www.google.com/calendar/feeds/default/private/full</id><updated>2007-02-05T22:04:50.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>w g</title><subtitle type='text'>w g</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full'></link><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full?max-results=25'></link><author><name>w g</name><email>wg@voiceme.net</email></author><generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><gCal:timezone value='America/Los_Angeles'></gCal:timezone><entry><id>http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig</id><published>2007-02-05T22:04:50.000Z</published><updated>2007-02-05T22:04:50.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=N2lxYzFybzBpaGM2OXZoc2lxM3VhYm9vaWcgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig/63306396290'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-07T13:30:00.000-08:00' endTime='2007-02-07T16:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c</id><published>2007-02-05T22:04:42.000Z</published><updated>2007-02-05T22:04:42.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=a3A0Z2lsNzZuMnZjcmt0OWthb3RqM3MxMmMgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c/63306396282'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-09T15:30:00.000-08:00' endTime='2007-02-09T18:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0</id><published>2007-02-05T22:04:35.000Z</published><updated>2007-02-05T22:04:35.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 6</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=Z2toYjQ4Zmo2OGxjcDE1ZmQxazAzdGpiajAgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0/63306396275'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-10T14:00:00.000-08:00' endTime='2007-02-10T17:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg</id><published>2007-02-05T22:04:29.000Z</published><updated>2007-02-05T22:04:29.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 5</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=MzJwNWc2OGNwZWFuM3Ayb2w3a2FuajM4c2cgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg/63306396269'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-09T09:00:00.000-08:00' endTime='2007-02-09T10:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4</id><published>2007-02-05T22:04:19.000Z</published><updated>2007-02-05T22:04:19.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=dGZxcHRoMjZjb25zaGRtYXYwYXBqZTF0ZjQgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4/63306396259'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-08T15:00:00.000-08:00' endTime='2007-02-08T17:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s</id><published>2007-02-05T22:04:07.000Z</published><updated>2007-02-05T22:04:07.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>Sharks at Anaheim</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b25ibzltaGJyNW02bW8zNTZub2c3dWVsNHMgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s/63306396247'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-07T19:00:00.000-08:00' endTime='2007-02-07T22:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k</id><published>2007-02-05T22:04:02.000Z</published><updated>2007-02-05T22:04:02.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>Sharks vs. ANAHEIM</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=dGpxcmQ5ZnZlNTc2aGllaDNzYTY3bnFsNWsgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k/63306396242'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-06T19:30:00.000-08:00' endTime='2007-02-06T22:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc</id><published>2007-02-05T22:03:52.000Z</published><updated>2007-02-05T22:03:52.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b3I2ZHRwbjA2NWY5bW50b25kNGpoMmRvY2Mgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc/63306396232'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-06T14:00:00.000-08:00' endTime='2007-02-06T15:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0</id><published>2007-02-05T22:03:36.000Z</published><updated>2007-02-05T22:03:36.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>lunch</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=azcwdjhvNGp0MWFmaTE3aGcyc3BhdnExYzBfMjAwNzAyMDZUMjAwMDAwWiB3Z0B2b2ljZW1lLm5ldA' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0/63306396216'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:recurrence>DTSTART;TZID=America/Los_Angeles:20070206T120000
+DURATION:PT3600S
+RRULE:FREQ=DAILY;WKST=SU
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+X-LIC-LOCATION:America/Los_Angeles
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+TZNAME:PST
+DTSTART:19701025T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+TZNAME:PDT
+DTSTART:19700405T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
+END:DAYLIGHT
+END:VTIMEZONE
+</gd:recurrence><gd:where valueString=''></gd:where><gd:reminder minutes='10'></gd:reminder></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124</id><published>2007-02-05T22:03:19.000Z</published><updated>2007-02-05T22:03:19.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 4</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=NmVlN2I4bm9oZHQwM3R2MGdrbm00djcxMjQgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124/63306396199'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-06T09:00:00.000-08:00' endTime='2007-02-06T11:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o</id><published>2007-02-05T22:03:11.000Z</published><updated>2007-02-05T22:03:11.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 3</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b2YxdmgxcjJxNWFxZHBsbzY1aThicWJuM28gd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o/63306396191'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-05T18:00:00.000-08:00' endTime='2007-02-05T19:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8</id><published>2007-02-05T22:02:40.000Z</published><updated>2007-02-05T22:03:04.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 2</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=czdhaGdmb21sZ2lpOXFia2dwZmJpbnI5dTggd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8/63306396184'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-05T16:30:00.000-08:00' endTime='2007-02-05T17:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k</id><published>2007-02-05T22:02:28.000Z</published><updated>2007-02-05T22:02:53.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 1</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=cmw4Zm9jZ2xmZTZqbmRxbDR1OGxnNzNxNWsgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k/63306396173'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-05T15:00:00.000-08:00' endTime='2007-02-05T16:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry></feed>
diff --git a/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz b/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz
new file mode 100644
index 0000000..6c86462
--- /dev/null
+++ b/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz
Binary files differ
diff --git a/tests/AndroidTests/res/raw/medium.xml b/tests/AndroidTests/res/raw/medium.xml
new file mode 100644
index 0000000..51c952c
--- /dev/null
+++ b/tests/AndroidTests/res/raw/medium.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<LinearLayout id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+	<TextView id="@+id/text" android:text="S" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView id="@+id/text" android:text="M" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView id="@+id/text" android:text="T" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView id="@+id/text" android:text="W" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView id="@+id/text" android:text="H" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+	<TextView id="@+id/text" android:text="F" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/AndroidTests/res/raw/small.xml b/tests/AndroidTests/res/raw/small.xml
new file mode 100644
index 0000000..2697fb8
--- /dev/null
+++ b/tests/AndroidTests/res/raw/small.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<view class="com.android.tests.InflateTest$ViewOne" id="@+id/viewOne" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
diff --git a/tests/AndroidTests/res/raw/text.txt b/tests/AndroidTests/res/raw/text.txt
new file mode 100644
index 0000000..3d8c519
--- /dev/null
+++ b/tests/AndroidTests/res/raw/text.txt
@@ -0,0 +1 @@
+OneTwoThreeFourFiveSixSevenEightNineTen
\ No newline at end of file
diff --git a/tests/AndroidTests/res/raw/youtube.xml b/tests/AndroidTests/res/raw/youtube.xml
new file mode 100644
index 0000000..fedaeac
--- /dev/null
+++ b/tests/AndroidTests/res/raw/youtube.xml
@@ -0,0 +1,1852 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<feed xmlns='http://www.w3.org/2005/Atom'
+      xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
+      xmlns:media='http://search.yahoo.com/mrss/'
+      xmlns:gd='http://schemas.google.com/g/2005'
+      xmlns:yt='http://gdata.youtube.com/schemas/2007'>
+    <id>http://dm5.google.com/feeds/standardfeeds/top_rated</id>
+    <updated>2007-05-01T18:13:20.333Z</updated>
+    <title type='text'>Top Rated - Beta</title>
+    <logo>http://www.youtube.com/img/pic_youtubelogo_123x63.gif</logo>
+    <link rel='alternate' type='text/html'
+          href='http://www.youtube.com/browse?s=tr'></link>
+    <link rel='http://schemas.google.com/g/2005#feed'
+          type='application/atom+xml'
+          href='http://dm5.google.com/feeds/standardfeeds/top_rated'></link>
+    <link rel='self' type='application/atom+xml'
+          href='http://dm5.google.com/feeds/standardfeeds/top_rated?start-index=1&amp;max-results=25'></link>
+    <link rel='next' type='application/atom+xml'
+          href='http://dm5.google.com/feeds/standardfeeds/top_rated?start-index=26&amp;max-results=25'></link>
+    <author>
+        <name>YouTube</name>
+        <uri>http://www.youtube.com/</uri>
+    </author>
+    <generator version='beta' uri='http://gdata.youtube.com/'>YouTube data API
+    </generator>
+    <openSearch:totalResults>99</openSearch:totalResults>
+    <openSearch:startIndex>1</openSearch:startIndex>
+    <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/nojWJ6-XmeQ</id>
+        <published>2006-09-01T15:13:19.000Z</published>
+        <updated>2006-09-01T15:13:19.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='comedy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='hilarious'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='funny'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Commercial'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='humor'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Condoms'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Comedy' label='Comedy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Banned'></category>
+        <title type='text'>Banned Commercial - Condoms</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/nojWJ6-XmeQ'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=nojWJ6-XmeQ'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/nojWJ6-XmeQ/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/nojWJ6-XmeQ/ratings'></link>
+        <author>
+            <name>bannedcommercials</name>
+            <uri>http://dm5.google.com/feeds/users/bannedcommercials</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Banned Commercial - Condoms</media:title>
+            <media:description type='plain'>Banned Commercial - Condoms
+            </media:description>
+            <media:keywords>Banned, Commercial, Condoms, funny, hilarious,
+                comedy, humor
+            </media:keywords>
+            <yt:duration seconds='45'></yt:duration>
+            <media:category label='Comedy'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Comedy
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=nojWJ6-XmeQ'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/nojWJ6-XmeQ/2.jpg'
+                             height='97' width='130'
+                             time='00:00:22.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/nojWJ6-XmeQ/1.jpg'
+                             height='97' width='130'
+                             time='00:00:11.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/nojWJ6-XmeQ/3.jpg'
+                             height='97' width='130'
+                             time='00:00:33.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/nojWJ6-XmeQ/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='65183' average='4.92'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/nojWJ6-XmeQ/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/JahdnOQ9XCA</id>
+        <published>2006-09-01T17:25:14.000Z</published>
+        <updated>2006-09-01T17:25:14.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='comedy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Voodoo'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='hilarious'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Clinton'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='funny'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Bill'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Commercial'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='very'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='doll'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='humor'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Entertainment' label='Entertainment'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Banned'></category>
+        <title type='text'>Banned Commercial - Bill Clinton Voodoo doll very
+            funny
+        </title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JahdnOQ9XCA'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=JahdnOQ9XCA'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JahdnOQ9XCA/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JahdnOQ9XCA/ratings'></link>
+        <author>
+            <name>bannedcommercials</name>
+            <uri>http://dm5.google.com/feeds/users/bannedcommercials</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Banned Commercial - Bill Clinton Voodoo
+                doll very funny
+            </media:title>
+            <media:description type='plain'>Banned Commercial - Bill Clinton
+                Voodoo doll very funny
+            </media:description>
+            <media:keywords>Banned, Commercial, Bill, Clinton, Voodoo, doll,
+                very, funny, humor, hilarious, comedy
+            </media:keywords>
+            <yt:duration seconds='69'></yt:duration>
+            <media:category label='Entertainment'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Entertainment
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=JahdnOQ9XCA'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/JahdnOQ9XCA/2.jpg'
+                             height='97' width='130'
+                             time='00:00:34.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JahdnOQ9XCA/1.jpg'
+                             height='97' width='130'
+                             time='00:00:17.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JahdnOQ9XCA/3.jpg'
+                             height='97' width='130'
+                             time='00:00:51.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JahdnOQ9XCA/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='60422' average='4.92'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/JahdnOQ9XCA/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/VcQIwbvGRKU</id>
+        <published>2006-09-03T05:32:33.000Z</published>
+        <updated>2006-09-03T05:32:33.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='hilarious'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='funny'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Commercial'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Talk'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Amazing'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='humor'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Entertainment' label='Entertainment'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='awesome'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='TV'></category>
+        <title type='text'>Amazing funny TV Commercial - Talk Talk</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/VcQIwbvGRKU'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=VcQIwbvGRKU'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/VcQIwbvGRKU/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/VcQIwbvGRKU/ratings'></link>
+        <author>
+            <name>bannedcommercials</name>
+            <uri>http://dm5.google.com/feeds/users/bannedcommercials</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Amazing funny TV Commercial - Talk Talk
+            </media:title>
+            <media:description type='plain'>Amazing funny TV Commercial - Talk
+                Talk
+            </media:description>
+            <media:keywords>Amazing, funny, TV, Commercial, Talk, humor,
+                hilarious, awesome
+            </media:keywords>
+            <yt:duration seconds='39'></yt:duration>
+            <media:category label='Entertainment'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Entertainment
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=VcQIwbvGRKU'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/VcQIwbvGRKU/2.jpg'
+                             height='97' width='130'
+                             time='00:00:19.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/VcQIwbvGRKU/1.jpg'
+                             height='97' width='130'
+                             time='00:00:09.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/VcQIwbvGRKU/3.jpg'
+                             height='97' width='130'
+                             time='00:00:29.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/VcQIwbvGRKU/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='47602' average='4.92'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/VcQIwbvGRKU/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/JsD6uEZsIsU</id>
+        <published>2006-11-28T16:42:47.000Z</published>
+        <updated>2006-11-28T16:42:47.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Mckee'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Andy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Guitar'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Acoustic'></category>
+        <title type='text'>Andy Mckee - Rylynn - Acoustic Guitar -
+            www.candyrat.com
+        </title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JsD6uEZsIsU'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=JsD6uEZsIsU'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JsD6uEZsIsU/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JsD6uEZsIsU/ratings'></link>
+        <author>
+            <name>rpoland</name>
+            <uri>http://dm5.google.com/feeds/users/rpoland</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Andy Mckee - Rylynn - Acoustic Guitar -
+                www.candyrat.com
+            </media:title>
+            <media:description type='plain'>Filmed Nov, 2006.
+
+                CD - Art of Motion
+
+                http://www.candyrat.com
+
+                Transcriptions Available at:
+
+                http://www.candyrat.com
+            </media:description>
+            <media:keywords>Andy, Mckee, Acoustic, Guitar</media:keywords>
+            <yt:duration seconds='315'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=JsD6uEZsIsU'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/JsD6uEZsIsU/2.jpg'
+                             height='97' width='130'
+                             time='00:02:37.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JsD6uEZsIsU/1.jpg'
+                             height='97' width='130'
+                             time='00:01:18.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JsD6uEZsIsU/3.jpg'
+                             height='97' width='130'
+                             time='00:03:56.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JsD6uEZsIsU/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='5035' average='4.92'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/JsD6uEZsIsU/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/dt1fB62cGbo</id>
+        <published>2006-11-19T16:02:11.000Z</published>
+        <updated>2006-11-19T16:02:11.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Toto'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Africa'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Mckee'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Andy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Guitar'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Fingerstyle'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Acoustic'></category>
+        <title type='text'>Andy Mckee - Africa - Toto - www.candyrat.com</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/dt1fB62cGbo'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=dt1fB62cGbo'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/dt1fB62cGbo/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/dt1fB62cGbo/ratings'></link>
+        <author>
+            <name>rpoland</name>
+            <uri>http://dm5.google.com/feeds/users/rpoland</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Andy Mckee - Africa - Toto -
+                www.candyrat.com
+            </media:title>
+            <media:description type='plain'>Andy Mckee
+
+                filmed, Nov, 2006.
+
+                CD - Dreamcatcher
+                http://www.candyrat.com
+
+                Transcriptions Available at:
+                http://www.candyrat.com
+            </media:description>
+            <media:keywords>Andy, Mckee, Acoustic, Guitar, Fingerstyle, Africa,
+                Toto
+            </media:keywords>
+            <yt:duration seconds='268'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=dt1fB62cGbo'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/dt1fB62cGbo/2.jpg'
+                             height='97' width='130'
+                             time='00:02:14'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/dt1fB62cGbo/1.jpg'
+                             height='97' width='130'
+                             time='00:01:07'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/dt1fB62cGbo/3.jpg'
+                             height='97' width='130'
+                             time='00:03:21'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/dt1fB62cGbo/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='4741' average='4.93'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/dt1fB62cGbo/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/Ddn4MGaS3N4</id>
+        <published>2006-11-25T21:38:20.000Z</published>
+        <updated>2006-11-25T21:38:20.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Mckee'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Andy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Guitar'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Acoustic'></category>
+        <title type='text'>Andy Mckee - Guitar - Drifting - www.candyrat.com
+        </title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/Ddn4MGaS3N4'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=Ddn4MGaS3N4'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/Ddn4MGaS3N4/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/Ddn4MGaS3N4/ratings'></link>
+        <author>
+            <name>rpoland</name>
+            <uri>http://dm5.google.com/feeds/users/rpoland</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Andy Mckee - Guitar - Drifting -
+                www.candyrat.com
+            </media:title>
+            <media:description type='plain'>Acoustic Guitar
+
+                Drifting - Andy Mckee's Original Song
+
+                filmed, Nov, 2006.
+
+                CD - Art of Motion
+
+                http://www.candyrat.com
+
+                Transcriptions Available at:
+
+                http://www.candyrat.com
+            </media:description>
+            <media:keywords>Acoustic, Guitar, Andy, Mckee</media:keywords>
+            <yt:duration seconds='198'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=Ddn4MGaS3N4'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/Ddn4MGaS3N4/2.jpg'
+                             height='97' width='130'
+                             time='00:01:39'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/Ddn4MGaS3N4/1.jpg'
+                             height='97' width='130'
+                             time='00:00:49.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/Ddn4MGaS3N4/3.jpg'
+                             height='97' width='130'
+                             time='00:02:28.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/Ddn4MGaS3N4/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='26323' average='4.90'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/Ddn4MGaS3N4/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/SmVAWKfJ4Go</id>
+        <published>2005-12-13T02:25:05.000Z</published>
+        <updated>2005-12-13T02:25:05.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Cash'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='hurt'></category>
+        <title type='text'>Cash Hurt</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/SmVAWKfJ4Go'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=SmVAWKfJ4Go'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/SmVAWKfJ4Go/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/SmVAWKfJ4Go/ratings'></link>
+        <author>
+            <name>beachbuggy</name>
+            <uri>http://dm5.google.com/feeds/users/beachbuggy</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Cash Hurt</media:title>
+            <media:description type='plain'>cash hurt</media:description>
+            <media:keywords>Cash, hurt</media:keywords>
+            <yt:duration seconds='241'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=SmVAWKfJ4Go'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/SmVAWKfJ4Go/2.jpg'
+                             height='97' width='130'
+                             time='00:02:00.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/SmVAWKfJ4Go/1.jpg'
+                             height='97' width='130'
+                             time='00:01:00.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/SmVAWKfJ4Go/3.jpg'
+                             height='97' width='130'
+                             time='00:03:00.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/SmVAWKfJ4Go/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='5328' average='4.91'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/SmVAWKfJ4Go/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/AbndgwfG22k</id>
+        <published>2006-06-18T18:07:46.000Z</published>
+        <updated>2006-06-18T18:07:46.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Tommy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Don'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Preston'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Kottke'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Emmanuel'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Ross'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Mongrain'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Hedges'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Erik'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Michael'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Reed'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Guitar'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Leo'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Acoustic'></category>
+        <title type='text'>"AirTap!"</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/AbndgwfG22k'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=AbndgwfG22k'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/AbndgwfG22k/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/AbndgwfG22k/ratings'></link>
+        <author>
+            <name>erikmongrain</name>
+            <uri>http://dm5.google.com/feeds/users/erikmongrain</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>"AirTap!"</media:title>
+            <media:description type='plain'>MY FIRST CD IS NOW AVAILABLE ON MY
+                WEBSITE IN MP3 FORMAT !!! IN STORE MAY 2007 !
+                www.erikmongrain.com
+
+                Myself playing a composition I made 6 years ago in the streets
+                of Spain when I was travelling around.That was on "Belle et Bum"
+                (popular music show in Quebec ).
+            </media:description>
+            <media:keywords>Acoustic, Guitar, Michael, Hedges, Preston, Reed,
+                Don, Ross, Erik, Mongrain, Tommy, Emmanuel, Leo, Kottke
+            </media:keywords>
+            <yt:duration seconds='180'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=AbndgwfG22k'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/AbndgwfG22k/2.jpg'
+                             height='97' width='130'
+                             time='00:01:30'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/AbndgwfG22k/1.jpg'
+                             height='97' width='130'
+                             time='00:00:45'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/AbndgwfG22k/3.jpg'
+                             height='97' width='130'
+                             time='00:02:15'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/AbndgwfG22k/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='6453' average='4.90'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/AbndgwfG22k/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/2Neop9OVaB8</id>
+        <published>2006-11-21T23:03:29.000Z</published>
+        <updated>2006-11-21T23:03:29.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Reel'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Minor'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Dunks'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Shinoda'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Skate'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Mike'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Name'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Fuse'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Flips'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Sports'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Entertainment' label='Entertainment'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Action'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Ties'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Remember'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Fort'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Highlight'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Scooter'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Tricks'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Rising'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='The'></category>
+        <title type='text'>Remember The Name - Highlight Reel Video</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/2Neop9OVaB8'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=2Neop9OVaB8'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/2Neop9OVaB8/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/2Neop9OVaB8/ratings'></link>
+        <author>
+            <name>fortminor</name>
+            <uri>http://dm5.google.com/feeds/users/fortminor</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Remember The Name - Highlight Reel Video
+            </media:title>
+            <media:description type='plain'>Fort Minor Remember The Name
+                "Highlight Reel" video - made from the winning video clips
+                submitted for the Fort Minor / Fuse Remember The Name contest -
+                congratulations to all the winners!
+            </media:description>
+            <media:keywords>Fort, Minor, Fuse, Highlight, Reel, Action, Sports,
+                Remember, The, Name, Rising, Ties, Mike, Shinoda, Skate,
+                Scooter, Tricks, Flips, Dunks
+            </media:keywords>
+            <yt:duration seconds='246'></yt:duration>
+            <media:category label='Entertainment'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Entertainment
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=2Neop9OVaB8'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/2Neop9OVaB8/2.jpg'
+                             height='97' width='130'
+                             time='00:02:03'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/2Neop9OVaB8/1.jpg'
+                             height='97' width='130'
+                             time='00:01:01.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/2Neop9OVaB8/3.jpg'
+                             height='97' width='130'
+                             time='00:03:04.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/2Neop9OVaB8/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='5535' average='4.90'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/2Neop9OVaB8/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/QKXWAE8YYxY</id>
+        <published>2006-02-03T00:07:12.000Z</published>
+        <updated>2006-02-03T00:07:12.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='MF'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Self'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Resident'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='MSI'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Evil'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Stupid'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Indulgence'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Four'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Mindless'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='RE4'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Games' label='Gadgets &amp; Games'></category>
+        <title type='text'>Resident Evil 4 -- Stupid MF</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/QKXWAE8YYxY'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=QKXWAE8YYxY'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/QKXWAE8YYxY/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/QKXWAE8YYxY/ratings'></link>
+        <author>
+            <name>raypinot</name>
+            <uri>http://dm5.google.com/feeds/users/raypinot</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Resident Evil 4 -- Stupid MF</media:title>
+            <media:description type='plain'>Video I made for Resident Evil 4
+                using "Separate Ways" and footage and that didn't make it into
+                my first video, "Vicinity of Obscenity" This video is done to
+                the song "Stupid MF" by Mindless Self Indulgence.
+
+                http://www.help-lara-and-ray.com/
+            </media:description>
+            <media:keywords>Resident, Evil, Four, RE4, Mindless, Self,
+                Indulgence, MSI, Stupid, MF
+            </media:keywords>
+            <yt:duration seconds='146'></yt:duration>
+            <media:category label='Gadgets &amp; Games'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Games
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=QKXWAE8YYxY'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/QKXWAE8YYxY/2.jpg'
+                             height='97' width='130'
+                             time='00:01:13'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/QKXWAE8YYxY/1.jpg'
+                             height='97' width='130'
+                             time='00:00:36.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/QKXWAE8YYxY/3.jpg'
+                             height='97' width='130'
+                             time='00:01:49.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/QKXWAE8YYxY/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='12632' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/QKXWAE8YYxY/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/zQoAUI84amI</id>
+        <published>2006-02-02T23:36:31.000Z</published>
+        <updated>2006-02-02T23:36:31.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Resident'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Evil'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='of'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='SOAD'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Obscenity'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Four'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Vicinity'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='System'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='RE4'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Games' label='Gadgets &amp; Games'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Down'></category>
+        <title type='text'>Resident Evil 4 -- Vicinity of Obscenity</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/zQoAUI84amI'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=zQoAUI84amI'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/zQoAUI84amI/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/zQoAUI84amI/ratings'></link>
+        <author>
+            <name>raypinot</name>
+            <uri>http://dm5.google.com/feeds/users/raypinot</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Resident Evil 4 -- Vicinity of Obscenity
+            </media:title>
+            <media:description type='plain'>Music video I made For Resident Evil
+                4 (PS2), using the System of a Down song, "Vicinity of
+                Obscenity"
+
+
+                http://www.help-lara-and-ray.com/
+            </media:description>
+            <media:keywords>Resident, Evil, Four, RE4, System, Down, SOAD,
+                Vicinity, of, Obscenity
+            </media:keywords>
+            <yt:duration seconds='168'></yt:duration>
+            <media:category label='Gadgets &amp; Games'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Games
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=zQoAUI84amI'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/zQoAUI84amI/2.jpg'
+                             height='97' width='130'
+                             time='00:01:24'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/zQoAUI84amI/1.jpg'
+                             height='97' width='130'
+                             time='00:00:42'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/zQoAUI84amI/3.jpg'
+                             height='97' width='130'
+                             time='00:02:06'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/zQoAUI84amI/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='9509' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/zQoAUI84amI/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/JzqumbhfxRo</id>
+        <published>2006-11-07T16:59:10.000Z</published>
+        <updated>2006-11-07T16:59:10.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='gjertsen'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='drums'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='and'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='editing'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='piano'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='amateur'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='drumkit'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='titties'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='norsk'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='ass'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Film' label='Film &amp; Animation'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='lasse'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='hyperactive'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='lassegg'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='norwegian'></category>
+        <title type='text'>Amateur - Lasse Gjertsen</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JzqumbhfxRo'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=JzqumbhfxRo'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JzqumbhfxRo/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/JzqumbhfxRo/ratings'></link>
+        <author>
+            <name>lassegg</name>
+            <uri>http://dm5.google.com/feeds/users/lassegg</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Amateur - Lasse Gjertsen</media:title>
+            <media:description type='plain'>I've taken my hyperactive editing
+                style a step further! Hope you'll enjoy it!
+
+                If you want to download the audio from this video, go to
+                http://www11.nrk.no/urort/user/?id=36781
+                It's a norwegian page where I uploaded some of my music. (Lytt =
+                Listen to, Last ned = Download)
+
+                Oh shit, I forgot to put this in the video, and now it's too
+                late to change it:
+                Thanks to my friend Mattis for letting me borrow the drum kit.
+                Also thanks to the person letting me use her piano, but she
+                didn't want her name here :P
+
+                And now; to you people saying I'm ripping off Michel Gondry:
+                I've seen his video with the drumkit called "Drumb and Drumber".
+                It's here on youtube somewhere. His video and my video are
+                different because of one very important detail: Gondy filmed
+                himself doing drumming sequences and LOOPED them, while I hit
+                each drum and piano chord seperately and edited them together.
+                This is a very big difference if you have any idea about video
+                editing. Actually, there is a short sequence of 5 sec where he
+                does cut the beat, but I didn't notice this until recently,
+                which makes me an idiot. But I still don't think it's a rip off,
+                only similar. SO one question to you guys: If I write a song
+                which includes the words "love" and "tight", am I ripping off
+                The Beatles?? :P I met Michel Gondry in Milan, Italy and asked
+                him. He didn't really give me a clear answer, but it seemed like
+                he thought so. Either that or he didn't like my clothes. Lol.
+            </media:description>
+            <media:keywords>amateur, lasse, gjertsen, drumkit, drums, piano,
+                music, norsk, norwegian, lassegg, hyperactive, editing, ass,
+                and, titties
+            </media:keywords>
+            <yt:duration seconds='192'></yt:duration>
+            <media:category label='Film &amp; Animation'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Film
+            </media:category>
+            <media:content
+                    url='rtsp://rtsp.youtube.com/youtube/videos/JzqumbhfxRo/video.3gp'
+                    type='video/3gpp' medium='video' isDefault='true'
+                    expression='full' duration='192'
+                    yt:format='1'></media:content>
+            <media:player
+                    url='http://www.youtube.com/watch?v=JzqumbhfxRo'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/JzqumbhfxRo/2.jpg'
+                             height='97' width='130'
+                             time='00:01:36'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JzqumbhfxRo/1.jpg'
+                             height='97' width='130'
+                             time='00:00:48'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JzqumbhfxRo/3.jpg'
+                             height='97' width='130'
+                             time='00:02:24'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/JzqumbhfxRo/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='35620' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/JzqumbhfxRo/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/YxQrPXPSVhQ</id>
+        <published>2006-06-17T16:04:49.000Z</published>
+        <updated>2006-06-17T16:04:49.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Evanescence'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <title type='text'>Evanescence</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/YxQrPXPSVhQ'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=YxQrPXPSVhQ'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/YxQrPXPSVhQ/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/YxQrPXPSVhQ/ratings'></link>
+        <author>
+            <name>luke4leanne</name>
+            <uri>http://dm5.google.com/feeds/users/luke4leanne</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Evanescence</media:title>
+            <media:description type='plain'>Evanescence-My Immortal
+            </media:description>
+            <media:keywords>Evanescence</media:keywords>
+            <yt:duration seconds='272'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=YxQrPXPSVhQ'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/YxQrPXPSVhQ/2.jpg'
+                             height='97' width='130'
+                             time='00:02:16'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/YxQrPXPSVhQ/1.jpg'
+                             height='97' width='130'
+                             time='00:01:08'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/YxQrPXPSVhQ/3.jpg'
+                             height='97' width='130'
+                             time='00:03:24'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/YxQrPXPSVhQ/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='5226' average='4.90'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/YxQrPXPSVhQ/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/O9mEKMz2Pvo</id>
+        <published>2006-02-15T12:14:08.000Z</published>
+        <updated>2006-02-15T12:14:08.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Weeps'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Shimabukuro'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='ukelele'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Gently'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Guitar'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='While'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='My'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Jake'></category>
+        <title type='text'>Jake Shimabukuro plays "While My Guitar Gently Weeps"
+        </title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/O9mEKMz2Pvo'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=O9mEKMz2Pvo'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/O9mEKMz2Pvo/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/O9mEKMz2Pvo/ratings'></link>
+        <author>
+            <name>strewth</name>
+            <uri>http://dm5.google.com/feeds/users/strewth</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Jake Shimabukuro plays "While My Guitar
+                Gently Weeps"
+            </media:title>
+            <media:description type='plain'>Jake Shimabukuro plays "While My
+                Guitar Gently Weeps" on the ukelele. Amazing.
+            </media:description>
+            <media:keywords>Jake, Shimabukuro, While, My, Guitar, Gently, Weeps,
+                ukelele
+            </media:keywords>
+            <yt:duration seconds='272'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=O9mEKMz2Pvo'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/O9mEKMz2Pvo/2.jpg'
+                             height='97' width='130'
+                             time='00:02:16'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/O9mEKMz2Pvo/1.jpg'
+                             height='97' width='130'
+                             time='00:01:08'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/O9mEKMz2Pvo/3.jpg'
+                             height='97' width='130'
+                             time='00:03:24'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/O9mEKMz2Pvo/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='6596' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/O9mEKMz2Pvo/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/rP3qL4UG1TI</id>
+        <published>2006-10-27T20:29:34.000Z</published>
+        <updated>2006-10-27T20:29:34.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='105'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Live'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Spears'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='whitemenace'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Entertainment' label='Entertainment'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Q101'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Woody'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Ravey'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='snoop'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='JayZ'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='dog'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='show'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='morning'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Aries'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Tony'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='radio'></category>
+        <title type='text'>The Woody show "Aries Spears" rap Live105.com</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/rP3qL4UG1TI'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=rP3qL4UG1TI'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/rP3qL4UG1TI/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/rP3qL4UG1TI/ratings'></link>
+        <author>
+            <name>Livemorningshow</name>
+            <uri>http://dm5.google.com/feeds/users/Livemorningshow</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>The Woody show "Aries Spears" rap
+                Live105.com
+            </media:title>
+            <media:description type='plain'>Live 105 Morning show "Aries Spears"
+                rap with Woody,Tony and Ravey. Edited By:
+                myspace.com/whitemenace
+            </media:description>
+            <media:keywords>Woody, Tony, Ravey, Live, 105, radio, morning, show,
+                Aries, Spears, JayZ, whitemenace, snoop, dog, Q101
+            </media:keywords>
+            <yt:duration seconds='135'></yt:duration>
+            <media:category label='Entertainment'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Entertainment
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=rP3qL4UG1TI'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/rP3qL4UG1TI/2.jpg'
+                             height='97' width='130'
+                             time='00:01:07.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/rP3qL4UG1TI/1.jpg'
+                             height='97' width='130'
+                             time='00:00:33.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/rP3qL4UG1TI/3.jpg'
+                             height='97' width='130'
+                             time='00:01:41.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/rP3qL4UG1TI/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='4856' average='4.90'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/rP3qL4UG1TI/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/4NFiu-V7StQ</id>
+        <published>2006-05-19T17:11:52.000Z</published>
+        <updated>2006-05-19T17:11:52.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Sims'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Chemical'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Film' label='Film &amp; Animation'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Helena'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Jaydee'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Romance'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Movie'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='MCR'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='machinima'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='My'></category>
+        <title type='text'>Helena - My Chemical Romance - Sims 2 version</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/4NFiu-V7StQ'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=4NFiu-V7StQ'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/4NFiu-V7StQ/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/4NFiu-V7StQ/ratings'></link>
+        <author>
+            <name>jaydee227</name>
+            <uri>http://dm5.google.com/feeds/users/jaydee227</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Helena - My Chemical Romance - Sims 2
+                version
+            </media:title>
+            <media:description type='plain'>This is the 3rd sims movie I made.
+                you need to watch it carefully or you won't understand the
+                story. But hope you enjoy :)
+
+                USEFUL LINKS:
+
+                Explanations to the storyline:
+                http://www.jd-movies.com/helenaexplained.html
+
+                List of the custom content:
+                http://www.jd-movies.com/helenacc.html
+
+                Movie FAQ:
+                http://www.jd-movies.com/helenafaq.html
+
+                Download link (MUCH better quality):
+                http://www.archive.org/download/helenasims2/Helena.wmv
+            </media:description>
+            <media:keywords>Helena, My, Chemical, Romance, MCR, Sims, Movie,
+                machinima, Jaydee
+            </media:keywords>
+            <yt:duration seconds='265'></yt:duration>
+            <media:category label='Film &amp; Animation'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Film
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=4NFiu-V7StQ'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/4NFiu-V7StQ/2.jpg'
+                             height='97' width='130'
+                             time='00:02:12.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/4NFiu-V7StQ/1.jpg'
+                             height='97' width='130'
+                             time='00:01:06.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/4NFiu-V7StQ/3.jpg'
+                             height='97' width='130'
+                             time='00:03:18.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/4NFiu-V7StQ/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='8446' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/4NFiu-V7StQ/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/bGFXKYvH39I</id>
+        <published>2006-06-21T17:23:54.000Z</published>
+        <updated>2006-06-21T17:23:54.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Three'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='grace'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='days'></category>
+        <title type='text'>three days grace-Animal I Have Become</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/bGFXKYvH39I'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=bGFXKYvH39I'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/bGFXKYvH39I/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/bGFXKYvH39I/ratings'></link>
+        <author>
+            <name>jollech69</name>
+            <uri>http://dm5.google.com/feeds/users/jollech69</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>three days grace-Animal I Have Become
+            </media:title>
+            <media:description type='plain'>By 3 days grace</media:description>
+            <media:keywords>Three, days, grace</media:keywords>
+            <yt:duration seconds='233'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=bGFXKYvH39I'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/bGFXKYvH39I/2.jpg'
+                             height='97' width='130'
+                             time='00:01:56.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/bGFXKYvH39I/1.jpg'
+                             height='97' width='130'
+                             time='00:00:58.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/bGFXKYvH39I/3.jpg'
+                             height='97' width='130'
+                             time='00:02:54.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/bGFXKYvH39I/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='5975' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/bGFXKYvH39I/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/V1_OkegYtZI</id>
+        <published>2007-03-17T10:45:49.000Z</published>
+        <updated>2007-03-17T10:45:49.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='series'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='spoof'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='dub'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='abridged'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='yugioh'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Comedy' label='Comedy'></category>
+        <title type='text'>Yu-Gi-Oh: The Abridged Series - Episode 19</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/V1_OkegYtZI'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=V1_OkegYtZI'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/V1_OkegYtZI/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/V1_OkegYtZI/ratings'></link>
+        <author>
+            <name>LittleKuriboh</name>
+            <uri>http://dm5.google.com/feeds/users/LittleKuriboh</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Yu-Gi-Oh: The Abridged Series - Episode 19
+            </media:title>
+            <media:description type='plain'>Imagine Yu-Gi-Oh condensed into
+                about nine minutes. That's basically what this is.
+
+                Yu-Gi-Oh is the property of Konami and Kazuki Takahasi.
+            </media:description>
+            <media:keywords>yugioh, abridged, series, dub, spoof
+            </media:keywords>
+            <yt:duration seconds='513'></yt:duration>
+            <media:category label='Comedy'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Comedy
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=V1_OkegYtZI'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/V1_OkegYtZI/2.jpg'
+                             height='97' width='130'
+                             time='00:04:16.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/V1_OkegYtZI/1.jpg'
+                             height='97' width='130'
+                             time='00:02:08.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/V1_OkegYtZI/3.jpg'
+                             height='97' width='130'
+                             time='00:06:24.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/V1_OkegYtZI/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='5912' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/V1_OkegYtZI/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/1A42U-pKP0U</id>
+        <published>2006-06-02T16:38:18.000Z</published>
+        <updated>2006-06-02T16:38:18.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Inside'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='FroM'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='LP'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='The'></category>
+        <title type='text'>™[LINKIN PARK-From The Inside]™</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/1A42U-pKP0U'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=1A42U-pKP0U'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/1A42U-pKP0U/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/1A42U-pKP0U/ratings'></link>
+        <author>
+            <name>linkin2789</name>
+            <uri>http://dm5.google.com/feeds/users/linkin2789</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>™[LINKIN PARK-From The Inside]™
+            </media:title>
+            <media:description type='plain'>Video de la canción From The Inside
+                de Linkin Park.
+            </media:description>
+            <media:keywords>LP, FroM, The, Inside</media:keywords>
+            <yt:duration seconds='175'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=1A42U-pKP0U'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/1A42U-pKP0U/2.jpg'
+                             height='97' width='130'
+                             time='00:01:27.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/1A42U-pKP0U/1.jpg'
+                             height='97' width='130'
+                             time='00:00:43.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/1A42U-pKP0U/3.jpg'
+                             height='97' width='130'
+                             time='00:02:11.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/1A42U-pKP0U/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='6824' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/1A42U-pKP0U/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/s-7UX1xSEfU</id>
+        <published>2006-07-18T17:06:52.000Z</published>
+        <updated>2006-07-18T17:06:52.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='spoof'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='dub'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='abridged'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='yugioh'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Comedy' label='Comedy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='yu-gi-oh'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='anime'></category>
+        <title type='text'>Yu-Gi-Oh: The Abridged Series (Episode 3)</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/s-7UX1xSEfU'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=s-7UX1xSEfU'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/s-7UX1xSEfU/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/s-7UX1xSEfU/ratings'></link>
+        <author>
+            <name>LittleKuriboh</name>
+            <uri>http://dm5.google.com/feeds/users/LittleKuriboh</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Yu-Gi-Oh: The Abridged Series (Episode 3)
+            </media:title>
+            <media:description type='plain'>Imagine "Yu-Gi-Oh" condensed into
+                four minutes. That's basically what this is.
+            </media:description>
+            <media:keywords>yugioh, yu-gi-oh, dub, spoof, anime, abridged
+            </media:keywords>
+            <yt:duration seconds='273'></yt:duration>
+            <media:category label='Comedy'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Comedy
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=s-7UX1xSEfU'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/s-7UX1xSEfU/2.jpg'
+                             height='97' width='130'
+                             time='00:02:16.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/s-7UX1xSEfU/1.jpg'
+                             height='97' width='130'
+                             time='00:01:08.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/s-7UX1xSEfU/3.jpg'
+                             height='97' width='130'
+                             time='00:03:24.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/s-7UX1xSEfU/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='5907' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/s-7UX1xSEfU/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/V6k3YlcYtS0</id>
+        <published>2006-08-05T22:15:41.000Z</published>
+        <updated>2006-08-05T22:15:41.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='spoof'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='dub'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='abridged'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='yugioh'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Comedy' label='Comedy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='yu-gi-oh'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='anime'></category>
+        <title type='text'>Yu-Gi-Oh: The Abridged Series (Episode 6)</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/V6k3YlcYtS0'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=V6k3YlcYtS0'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/V6k3YlcYtS0/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/V6k3YlcYtS0/ratings'></link>
+        <author>
+            <name>LittleKuriboh</name>
+            <uri>http://dm5.google.com/feeds/users/LittleKuriboh</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Yu-Gi-Oh: The Abridged Series (Episode 6)
+            </media:title>
+            <media:description type='plain'>Imagine "Yu-Gi-Oh" condensed into
+                four... uh, six minutes. That's basically what this is.
+
+                Yu-Gi-Oh belongs to Kazuki Takahashi
+            </media:description>
+            <media:keywords>yu-gi-oh, yugioh, abridged, dub, spoof, anime
+            </media:keywords>
+            <yt:duration seconds='355'></yt:duration>
+            <media:category label='Comedy'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Comedy
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=V6k3YlcYtS0'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/V6k3YlcYtS0/2.jpg'
+                             height='97' width='130'
+                             time='00:02:57.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/V6k3YlcYtS0/1.jpg'
+                             height='97' width='130'
+                             time='00:01:28.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/V6k3YlcYtS0/3.jpg'
+                             height='97' width='130'
+                             time='00:04:26.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/V6k3YlcYtS0/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='6447' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/V6k3YlcYtS0/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/HTKs5ZT16PM</id>
+        <published>2006-10-23T18:15:56.000Z</published>
+        <updated>2006-10-23T18:15:56.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='series'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='spoof'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='dub'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='abridged'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='yugioh'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Comedy' label='Comedy'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='anime'></category>
+        <title type='text'>Yu-Gi-Oh: The Abridged Series (Episode 13)</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/HTKs5ZT16PM'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=HTKs5ZT16PM'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/HTKs5ZT16PM/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/HTKs5ZT16PM/ratings'></link>
+        <author>
+            <name>LittleKuriboh</name>
+            <uri>http://dm5.google.com/feeds/users/LittleKuriboh</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Yu-Gi-Oh: The Abridged Series (Episode 13)
+            </media:title>
+            <media:description type='plain'>Please ignore the imposter videos.
+
+                Imagine "Yu-Gi-Oh" condensed into five/six minutes. That's
+                basically what this is.
+
+                Yu-Gi-Oh belongs to Kazuki Takahashi
+            </media:description>
+            <media:keywords>yugioh, abridged, series, anime, spoof, dub
+            </media:keywords>
+            <yt:duration seconds='349'></yt:duration>
+            <media:category label='Comedy'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Comedy
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=HTKs5ZT16PM'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/HTKs5ZT16PM/2.jpg'
+                             height='97' width='130'
+                             time='00:02:54.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/HTKs5ZT16PM/1.jpg'
+                             height='97' width='130'
+                             time='00:01:27.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/HTKs5ZT16PM/3.jpg'
+                             height='97' width='130'
+                             time='00:04:21.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/HTKs5ZT16PM/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='7255' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/HTKs5ZT16PM/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/MePzWtHqrso</id>
+        <published>2006-06-28T00:21:59.000Z</published>
+        <updated>2006-06-28T00:21:59.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Benjamin'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Breaking'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Music' label='Music'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Diary'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Jane'></category>
+        <title type='text'>Breaking Benjamin - "The Diary of Jane"</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/MePzWtHqrso'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=MePzWtHqrso'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/MePzWtHqrso/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/MePzWtHqrso/ratings'></link>
+        <author>
+            <name>BrienTA</name>
+            <uri>http://dm5.google.com/feeds/users/BrienTA</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Breaking Benjamin - "The Diary of Jane"
+            </media:title>
+            <media:description type='plain'>Breaking Benjamin - "The Diary of
+                Jane"
+            </media:description>
+            <media:keywords>Breaking, Benjamin, Diary, Jane</media:keywords>
+            <yt:duration seconds='207'></yt:duration>
+            <media:category label='Music'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Music
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=MePzWtHqrso'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/MePzWtHqrso/2.jpg'
+                             height='97' width='130'
+                             time='00:01:43.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/MePzWtHqrso/1.jpg'
+                             height='97' width='130'
+                             time='00:00:51.750'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/MePzWtHqrso/3.jpg'
+                             height='97' width='130'
+                             time='00:02:35.250'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/MePzWtHqrso/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='6298' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/MePzWtHqrso/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/ElrldD02if0</id>
+        <published>2006-11-20T19:41:52.000Z</published>
+        <updated>2006-11-20T19:41:52.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='ms.paint'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='paint'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='how'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='good'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='automobile'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='custom'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='art'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='comaro'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='foose'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='chip'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='artistic'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='concept'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='great'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='awsome'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Film' label='Film &amp; Animation'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='design'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='draw'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='car'></category>
+        <title type='text'>Re: How to draw a car in MS. Paint</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/ElrldD02if0'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=ElrldD02if0'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/ElrldD02if0/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/ElrldD02if0/ratings'></link>
+        <author>
+            <name>picster</name>
+            <uri>http://dm5.google.com/feeds/users/picster</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>Re: How to draw a car in MS. Paint
+            </media:title>
+            <media:description type='plain'>WATCH MY NEW VIDEO!!!!
+                http://www.youtube.com/watch?v=vUWqRhReaZk
+
+                ----
+                Wow! So many nice comments and views :)
+                I'm very happy you all like it.
+
+                And thank you very much for all the nice emails!
+            </media:description>
+            <media:keywords>car, art, paint, draw, automobile, comaro, custom,
+                concept, how, ms.paint, great, good, awsome, design, artistic,
+                chip, foose
+            </media:keywords>
+            <yt:duration seconds='318'></yt:duration>
+            <media:category label='Film &amp; Animation'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Film
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=ElrldD02if0'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/ElrldD02if0/2.jpg'
+                             height='97' width='130'
+                             time='00:02:39'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/ElrldD02if0/1.jpg'
+                             height='97' width='130'
+                             time='00:01:19.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/ElrldD02if0/3.jpg'
+                             height='97' width='130'
+                             time='00:03:58.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/ElrldD02if0/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='9986' average='4.88'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/ElrldD02if0/comments'></gd:feedLink>
+    </entry>
+    <entry>
+        <id>http://dm5.google.com/feeds/videos/Ox0c_1l9al4</id>
+        <published>2006-07-04T01:56:27.000Z</published>
+        <updated>2006-07-04T01:56:27.000Z</updated>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Cook'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Naruto'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat'
+                  term='Dane'></category>
+        <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat'
+                  term='Comedy' label='Comedy'></category>
+        <title type='text'>AMV Comedians 2 (Dane Cook)</title>
+        <link rel='self' type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/Ox0c_1l9al4'></link>
+        <link rel='alternate' type='text/html'
+              href='http://www.youtube.com/watch?v=Ox0c_1l9al4'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.responses'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/Ox0c_1l9al4/responses'></link>
+        <link rel='http://gdata.youtube.com/schemas/2007#video.ratings'
+              type='application/atom+xml'
+              href='http://dm5.google.com/feeds/videos/Ox0c_1l9al4/ratings'></link>
+        <author>
+            <name>Rubix89</name>
+            <uri>http://dm5.google.com/feeds/users/Rubix89</uri>
+        </author>
+        <media:group>
+            <media:title type='plain'>AMV Comedians 2 (Dane Cook)</media:title>
+            <media:description type='plain'>Anime: Naruto
+                Comedian: Dane Cook
+                I know I already did Dane Cook, but I couldnt pass up this joke.
+                http://www.animemusicvideos.org/members/members_videoinfo.php?v=130820
+            </media:description>
+            <media:keywords>Naruto, Dane, Cook</media:keywords>
+            <yt:duration seconds='126'></yt:duration>
+            <media:category label='Comedy'
+                            scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>
+                Comedy
+            </media:category>
+            <media:player
+                    url='http://www.youtube.com/watch?v=Ox0c_1l9al4'></media:player>
+            <media:thumbnail url='http://img.youtube.com/vi/Ox0c_1l9al4/2.jpg'
+                             height='97' width='130'
+                             time='00:01:03'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/Ox0c_1l9al4/1.jpg'
+                             height='97' width='130'
+                             time='00:00:31.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/Ox0c_1l9al4/3.jpg'
+                             height='97' width='130'
+                             time='00:01:34.500'></media:thumbnail>
+            <media:thumbnail url='http://img.youtube.com/vi/Ox0c_1l9al4/0.jpg'
+                             height='240' width='320'></media:thumbnail>
+        </media:group>
+        <gd:rating min='1' max='5' numRaters='6727' average='4.89'></gd:rating>
+        <gd:feedLink rel='comments'
+                     href='http://dm5.google.com/feeds/videos/Ox0c_1l9al4/comments'></gd:feedLink>
+    </entry>
+</feed>
diff --git a/tests/AndroidTests/res/values-12key/configVarying.xml b/tests/AndroidTests/res/values-12key/configVarying.xml
new file mode 100644
index 0000000..14ce1a7
--- /dev/null
+++ b/tests/AndroidTests/res/values-12key/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple 12key</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag 12key</item>
+    </bag>
+    <item type="configVarying" name="simple_12key">only simple 12key</item>
+    <bag type="configVarying" name="bag_12key">
+        <item name="testString">only bag 12key</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-320x200/configVarying.xml b/tests/AndroidTests/res/values-320x200/configVarying.xml
new file mode 100644
index 0000000..035e55e
--- /dev/null
+++ b/tests/AndroidTests/res/values-320x200/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple 320x200</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag 320x200</item>
+    </bag>
+    <item type="configVarying" name="simple_320x200">only simple 320x200</item>
+    <bag type="configVarying" name="bag_320x200">
+        <item name="testString">only bag 320x200</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-480x320/configVarying.xml b/tests/AndroidTests/res/values-480x320/configVarying.xml
new file mode 100644
index 0000000..8b28d89
--- /dev/null
+++ b/tests/AndroidTests/res/values-480x320/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple 480x320</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag 480x320</item>
+    </bag>
+    <item type="configVarying" name="simple_480x320">only simple 480x320</item>
+    <bag type="configVarying" name="bag_480x320">
+        <item name="testString">only bag 480x320</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-cs/strings.xml b/tests/AndroidTests/res/values-cs/strings.xml
new file mode 100644
index 0000000..bd402c7
--- /dev/null
+++ b/tests/AndroidTests/res/values-cs/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ 
+    <plurals name="plurals_test">
+        <item quantity="one">A Czech dog</item>
+        <item quantity="few">Few Czech dogs</item>
+        <item quantity="other">Some Czech dogs</item>
+    </plurals>
+</resources>
+
diff --git a/tests/AndroidTests/res/values-dpad/configVarying.xml b/tests/AndroidTests/res/values-dpad/configVarying.xml
new file mode 100644
index 0000000..c8d5767
--- /dev/null
+++ b/tests/AndroidTests/res/values-dpad/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple dpad</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag dpad</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-finger/configVarying.xml b/tests/AndroidTests/res/values-finger/configVarying.xml
new file mode 100644
index 0000000..efe4758
--- /dev/null
+++ b/tests/AndroidTests/res/values-finger/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple finger</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag finger</item>
+    </bag>
+    <item type="configVarying" name="simple_finger">only simple finger</item>
+    <bag type="configVarying" name="bag_finger">
+        <item name="testString">only bag finger</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-keysexposed/configVarying.xml b/tests/AndroidTests/res/values-keysexposed/configVarying.xml
new file mode 100644
index 0000000..2380e7e
--- /dev/null
+++ b/tests/AndroidTests/res/values-keysexposed/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple keysexposed</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag keysexposed</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-keyshidden/configVarying.xml b/tests/AndroidTests/res/values-keyshidden/configVarying.xml
new file mode 100644
index 0000000..fdffc4d
--- /dev/null
+++ b/tests/AndroidTests/res/values-keyshidden/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple keyshidden</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag keyshidden</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-mcc111/configVarying.xml b/tests/AndroidTests/res/values-mcc111/configVarying.xml
new file mode 100644
index 0000000..16b13a5
--- /dev/null
+++ b/tests/AndroidTests/res/values-mcc111/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple mcc111</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag mcc111</item>
+    </bag>
+    <item type="configVarying" name="simple_mcc111">only simple mcc111</item>
+    <bag type="configVarying" name="bag_mcc111">
+        <item name="testString">only bag mcc111</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-mnc222/configVarying.xml b/tests/AndroidTests/res/values-mnc222/configVarying.xml
new file mode 100644
index 0000000..7f68729
--- /dev/null
+++ b/tests/AndroidTests/res/values-mnc222/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple mnc222</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag mnc222</item>
+    </bag>
+    <item type="configVarying" name="simple_mnc222">only simple mnc222</item>
+    <bag type="configVarying" name="bag_mnc222">
+        <item name="testString">only bag mnc222</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-nokeys/configVarying.xml b/tests/AndroidTests/res/values-nokeys/configVarying.xml
new file mode 100644
index 0000000..71f7e0b
--- /dev/null
+++ b/tests/AndroidTests/res/values-nokeys/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple nokeys</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag nokeys</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-nonav/configVarying.xml b/tests/AndroidTests/res/values-nonav/configVarying.xml
new file mode 100644
index 0000000..1254920
--- /dev/null
+++ b/tests/AndroidTests/res/values-nonav/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple nonav</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag nonav</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-notouch/configVarying.xml b/tests/AndroidTests/res/values-notouch/configVarying.xml
new file mode 100644
index 0000000..8a71de4
--- /dev/null
+++ b/tests/AndroidTests/res/values-notouch/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple notouch</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag notouch</item>
+    </bag>
+    <item type="configVarying" name="simple_notouch">only simple notouch</item>
+    <bag type="configVarying" name="bag_notouch">
+        <item name="testString">only bag notouch</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-qwerty/configVarying.xml b/tests/AndroidTests/res/values-qwerty/configVarying.xml
new file mode 100644
index 0000000..939f682
--- /dev/null
+++ b/tests/AndroidTests/res/values-qwerty/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple qwerty</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag qwerty</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-stylus/configVarying.xml b/tests/AndroidTests/res/values-stylus/configVarying.xml
new file mode 100644
index 0000000..87df119
--- /dev/null
+++ b/tests/AndroidTests/res/values-stylus/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple stylus</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag stylus</item>
+    </bag>
+    <item type="configVarying" name="simple_stylus">only simple stylus</item>
+    <bag type="configVarying" name="bag_stylus">
+        <item name="testString">only bag stylus</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-trackball/configVarying.xml b/tests/AndroidTests/res/values-trackball/configVarying.xml
new file mode 100644
index 0000000..0dec300
--- /dev/null
+++ b/tests/AndroidTests/res/values-trackball/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple trackball</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag trackball</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-wheel/configVarying.xml b/tests/AndroidTests/res/values-wheel/configVarying.xml
new file mode 100644
index 0000000..6164855
--- /dev/null
+++ b/tests/AndroidTests/res/values-wheel/configVarying.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple wheel</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag wheel</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-xx-rYY/configVarying.xml b/tests/AndroidTests/res/values-xx-rYY/configVarying.xml
new file mode 100644
index 0000000..4e52db9
--- /dev/null
+++ b/tests/AndroidTests/res/values-xx-rYY/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple xx-rYY</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag xx-rYY</item>
+    </bag>
+    <item type="configVarying" name="simple_xx_rYY">only simple xx_rYY</item>
+    <bag type="configVarying" name="bag_xx_rYY">
+        <item name="testString">only bag xx_rYY</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values-xx/configVarying.xml b/tests/AndroidTests/res/values-xx/configVarying.xml
new file mode 100644
index 0000000..e50649d
--- /dev/null
+++ b/tests/AndroidTests/res/values-xx/configVarying.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple xx</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag xx</item>
+    </bag>
+    <item type="configVarying" name="simple_xx">only simple xx</item>
+    <bag type="configVarying" name="bag_xx">
+        <item name="testString">only bag xx</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values/arrays.xml b/tests/AndroidTests/res/values/arrays.xml
new file mode 100644
index 0000000..20ab407
--- /dev/null
+++ b/tests/AndroidTests/res/values/arrays.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="integer" name="reference" format="integer">101</item>
+    
+    <!--
+    <array name="generic">
+        <item>zero</item>
+        <item>1</item>
+        <item>@string/reference</item>
+    </array>
+    <array name="genericStrings" format="string">
+        <item>zero</item>
+        <item>1</item>
+        <item>@string/reference</item>
+    </array>
+    -->
+    <string-array name="strings">
+        <item>zero</item>
+        <item>1</item>
+        <item>@string/reference</item>
+    </string-array>
+    <integer-array name="integers">
+        <item>0</item>
+        <item>1</item>
+        <item>@integer/reference</item>
+    </integer-array>
+</resources>
diff --git a/tests/AndroidTests/res/values/attrs.xml b/tests/AndroidTests/res/values/attrs.xml
new file mode 100644
index 0000000..d3a31ca
--- /dev/null
+++ b/tests/AndroidTests/res/values/attrs.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <attr name="testEnum">
+        <enum name="val1" value="1" />
+        <enum name="val2" value="2" />
+        <enum name="val10" value="10" />
+    </attr>
+
+    <attr name="testFlags">
+        <flag name="bit1" value="0x1" />
+        <flag name="bit2" value="0x2" />
+        <flag name="bit31" value="0x40000000" />
+    </attr>
+
+    <attr name="testString" format="string" />
+    
+    <declare-styleable name="EnumStyle">
+        <attr name="testEnum" />
+    </declare-styleable>
+
+    <declare-styleable name="FlagStyle">
+        <attr name="testFlags" />
+    </declare-styleable>
+    
+    <declare-styleable name="TestConfig">
+        <attr name="testString" />
+    </declare-styleable>
+</resources>
+
diff --git a/tests/AndroidTests/res/values/bools.xml b/tests/AndroidTests/res/values/bools.xml
new file mode 100644
index 0000000..ffa8955
--- /dev/null
+++ b/tests/AndroidTests/res/values/bools.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+	<bool name="trueRes">true</bool>
+	<bool name="falseRes">false</bool>
+</resources>
diff --git a/tests/AndroidTests/res/values/configVarying.xml b/tests/AndroidTests/res/values/configVarying.xml
new file mode 100644
index 0000000..c4a20ad
--- /dev/null
+++ b/tests/AndroidTests/res/values/configVarying.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item type="configVarying" name="simple">simple default</item>
+    <bag type="configVarying" name="bag">
+        <item name="testString">bag default</item>
+    </bag>
+    
+    <item type="configVarying" name="simple_default">only simple default</item>
+    <bag type="configVarying" name="bag_default">
+        <item name="testString">only bag default</item>
+    </bag>
+</resources>
diff --git a/tests/AndroidTests/res/values/dimens.xml b/tests/AndroidTests/res/values/dimens.xml
new file mode 100644
index 0000000..72d1010
--- /dev/null
+++ b/tests/AndroidTests/res/values/dimens.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item name="frac100perc" type="dimen" format="fraction">100%</item>
+    <item name="frac1perc" type="dimen" format="fraction">1%</item>
+    <item name="fracp1perc" type="dimen" format="fraction">.1%</item>
+    <item name="fracp01perc" type="dimen" format="fraction">.01%</item>
+    <item name="frac0perc" type="dimen" format="fraction">0%</item>
+    <item name="frac1p1perc" type="dimen" format="fraction">1.1%</item>
+    <item name="frac100p1perc" type="dimen" format="fraction">100.1%</item>
+    <item name="frac25510perc" type="dimen" format="fraction">25510%</item>
+    <item name="frac25610perc" type="dimen" format="fraction">25610%</item>
+    <item name="frac6553510perc" type="dimen" format="fraction">6553510%</item>
+    <item name="frac6553610perc" type="dimen" format="fraction">6553610%</item>
+
+    <item name="frac100pperc" type="dimen" format="fraction">100%p</item>
+    <item name="frac1pperc" type="dimen" format="fraction">1%p</item>
+    <item name="fracp1pperc" type="dimen" format="fraction">.1%p</item>
+    <item name="fracp01pperc" type="dimen" format="fraction">.01%p</item>
+    <item name="frac0pperc" type="dimen" format="fraction">0%p</item>
+    <item name="frac1p1pperc" type="dimen" format="fraction">1.1%p</item>
+    <item name="frac100p1pperc" type="dimen" format="fraction">100.1%p</item>
+    <item name="frac25510pperc" type="dimen" format="fraction">25510%p</item>
+    <item name="frac25610pperc" type="dimen" format="fraction">25610%p</item>
+    <item name="frac6553510pperc" type="dimen" format="fraction">6553510%p</item>
+    <item name="frac6553610pperc" type="dimen" format="fraction">6553610%p</item> 
+</resources>
+
diff --git a/tests/AndroidTests/res/values/strings.xml b/tests/AndroidTests/res/values/strings.xml
new file mode 100644
index 0000000..21c72cf
--- /dev/null
+++ b/tests/AndroidTests/res/values/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="permlab_testGranted">Test Granted</string>
+    <string name="permdesc_testGranted">Used for running unit tests, for
+        testing operations where we have the permission.</string>
+    <string name="permlab_testDenied">Test Denied</string>
+    <string name="permdesc_testDenied">Used for running unit tests, for
+        testing operations where we do not have the permission.</string>
+
+    <string name="layout_five_text_text">S</string>
+
+    <string name="layout_four_text_text">S</string>
+
+    <string name="layout_six_text_text">S</string>
+
+    <string name="coerceIntegerToString">100</string>
+    <string name="coerceBooleanToString">true</string>
+    <string name="coerceColorToString">#fff</string>
+    <string name="coerceFloatToString">100.0</string>
+    <string name="coerceDimensionToString">100px</string>
+    <string name="coerceFractionToString">100<xliff:g id="percent">%</xliff:g></string>
+
+    <string name="formattedStringNone">Format[]</string>
+    <string name="formattedStringOne">Format[<xliff:g id="format">%d</xliff:g>]</string>
+    <string name="formattedStringTwo">Format[<xliff:g id="format">%3$d,%2$s</xliff:g>]</string>
+    
+    <string name="reference">here</string>
+    
+    <string name="metadata_text">text</string>
+
+    <string name="menu_test">test</string>
+    
+    <plurals name="plurals_test">
+        <item quantity="one">A dog</item>
+        <item quantity="other">Some dogs</item>
+    </plurals>
+    
+<!--    <string name="layout_six_text_text">F</string> -->
+</resources>
diff --git a/tests/AndroidTests/res/values/styles.xml b/tests/AndroidTests/res/values/styles.xml
new file mode 100644
index 0000000..6c60e21
--- /dev/null
+++ b/tests/AndroidTests/res/values/styles.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="TestEnum1">
+        <item name="testEnum">val1</item>
+    </style>
+    <style name="TestEnum2">
+        <item name="testEnum">val2</item>
+    </style>
+    <style name="TestEnum10">
+        <item name="testEnum">val10</item>
+    </style>
+
+    <style name="TestFlag1">
+        <item name="testFlags">bit1</item>
+    </style>
+    <style name="TestFlag2">
+        <item name="testFlags">bit2</item>
+    </style>
+    <style name="TestFlag31">
+        <item name="testFlags">bit31</item>
+    </style>
+    <style name="TestFlag1And2">
+        <item name="testFlags">bit1|bit2</item>
+    </style>
+    <style name="TestFlag1And2And31">
+        <item name="testFlags">bit1|bit2|bit31</item>
+    </style>
+    
+    <style name="TestEnum1.EmptyInherit">
+    </style>
+</resources>
diff --git a/tests/AndroidTests/res/xml/calendar.xml b/tests/AndroidTests/res/xml/calendar.xml
new file mode 100644
index 0000000..1adcd74
--- /dev/null
+++ b/tests/AndroidTests/res/xml/calendar.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:gCal='http://schemas.google.com/gCal/2005'><id>http://www.google.com/calendar/feeds/default/private/full</id><updated>2007-02-05T22:04:50.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>w g</title><subtitle type='text'>w g</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full'></link><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full?max-results=25'></link><author><name>w g</name><email>wg@voiceme.net</email></author><generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><gCal:timezone value='America/Los_Angeles'></gCal:timezone><entry><id>http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig</id><published>2007-02-05T22:04:50.000Z</published><updated>2007-02-05T22:04:50.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=N2lxYzFybzBpaGM2OXZoc2lxM3VhYm9vaWcgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig/63306396290'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-07T13:30:00.000-08:00' endTime='2007-02-07T16:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c</id><published>2007-02-05T22:04:42.000Z</published><updated>2007-02-05T22:04:42.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=a3A0Z2lsNzZuMnZjcmt0OWthb3RqM3MxMmMgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c/63306396282'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-09T15:30:00.000-08:00' endTime='2007-02-09T18:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0</id><published>2007-02-05T22:04:35.000Z</published><updated>2007-02-05T22:04:35.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 6</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=Z2toYjQ4Zmo2OGxjcDE1ZmQxazAzdGpiajAgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0/63306396275'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-10T14:00:00.000-08:00' endTime='2007-02-10T17:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg</id><published>2007-02-05T22:04:29.000Z</published><updated>2007-02-05T22:04:29.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 5</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=MzJwNWc2OGNwZWFuM3Ayb2w3a2FuajM4c2cgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg/63306396269'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-09T09:00:00.000-08:00' endTime='2007-02-09T10:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4</id><published>2007-02-05T22:04:19.000Z</published><updated>2007-02-05T22:04:19.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=dGZxcHRoMjZjb25zaGRtYXYwYXBqZTF0ZjQgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4/63306396259'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-08T15:00:00.000-08:00' endTime='2007-02-08T17:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s</id><published>2007-02-05T22:04:07.000Z</published><updated>2007-02-05T22:04:07.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>Sharks at Anaheim</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b25ibzltaGJyNW02bW8zNTZub2c3dWVsNHMgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s/63306396247'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-07T19:00:00.000-08:00' endTime='2007-02-07T22:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k</id><published>2007-02-05T22:04:02.000Z</published><updated>2007-02-05T22:04:02.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>Sharks vs. ANAHEIM</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=dGpxcmQ5ZnZlNTc2aGllaDNzYTY3bnFsNWsgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k/63306396242'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-06T19:30:00.000-08:00' endTime='2007-02-06T22:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc</id><published>2007-02-05T22:03:52.000Z</published><updated>2007-02-05T22:03:52.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b3I2ZHRwbjA2NWY5bW50b25kNGpoMmRvY2Mgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc/63306396232'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-06T14:00:00.000-08:00' endTime='2007-02-06T15:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0</id><published>2007-02-05T22:03:36.000Z</published><updated>2007-02-05T22:03:36.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>lunch</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=azcwdjhvNGp0MWFmaTE3aGcyc3BhdnExYzBfMjAwNzAyMDZUMjAwMDAwWiB3Z0B2b2ljZW1lLm5ldA' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0/63306396216'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:recurrence>DTSTART;TZID=America/Los_Angeles:20070206T120000
+DURATION:PT3600S
+RRULE:FREQ=DAILY;WKST=SU
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+X-LIC-LOCATION:America/Los_Angeles
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+TZNAME:PST
+DTSTART:19701025T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+TZNAME:PDT
+DTSTART:19700405T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
+END:DAYLIGHT
+END:VTIMEZONE
+</gd:recurrence><gd:where valueString=''></gd:where><gd:reminder minutes='10'></gd:reminder></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124</id><published>2007-02-05T22:03:19.000Z</published><updated>2007-02-05T22:03:19.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 4</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=NmVlN2I4bm9oZHQwM3R2MGdrbm00djcxMjQgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124/63306396199'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-06T09:00:00.000-08:00' endTime='2007-02-06T11:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o</id><published>2007-02-05T22:03:11.000Z</published><updated>2007-02-05T22:03:11.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 3</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b2YxdmgxcjJxNWFxZHBsbzY1aThicWJuM28gd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o/63306396191'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-05T18:00:00.000-08:00' endTime='2007-02-05T19:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8</id><published>2007-02-05T22:02:40.000Z</published><updated>2007-02-05T22:03:04.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 2</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=czdhaGdmb21sZ2lpOXFia2dwZmJpbnI5dTggd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8/63306396184'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-05T16:30:00.000-08:00' endTime='2007-02-05T17:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k</id><published>2007-02-05T22:02:28.000Z</published><updated>2007-02-05T22:02:53.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 1</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=cmw4Zm9jZ2xmZTZqbmRxbDR1OGxnNzNxNWsgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k/63306396173'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-05T15:00:00.000-08:00' endTime='2007-02-05T16:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry></feed>
diff --git a/tests/AndroidTests/res/xml/metadata.xml b/tests/AndroidTests/res/xml/metadata.xml
new file mode 100644
index 0000000..e352f27
--- /dev/null
+++ b/tests/AndroidTests/res/xml/metadata.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<thedata xmlns:android="http://schemas.android.com/apk/res/android"
+    rawText="some raw text"
+    rawColor="#ffffff00"
+    android:color="#f00"
+    android:text="@string/metadata_text"
+
+/>
diff --git a/tests/AndroidTests/res/xml/metadata_app.xml b/tests/AndroidTests/res/xml/metadata_app.xml
new file mode 100644
index 0000000..c37e6ba
--- /dev/null
+++ b/tests/AndroidTests/res/xml/metadata_app.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<thedata xmlns:android="http://schemas.android.com/apk/res/android"
+    rawText="some raw text"
+    rawColor="#ffffff00"
+    android:color="#f00"
+    android:text="@string/metadata_text"
+    appInfo="true"
+
+/>
diff --git a/tests/AndroidTests/res/xml/searchable.xml b/tests/AndroidTests/res/xml/searchable.xml
new file mode 100644
index 0000000..a40d53d
--- /dev/null
+++ b/tests/AndroidTests/res/xml/searchable.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<searchable xmlns:android="http://schemas.android.com/apk/res/android"
+    android:label="SearchManagerTest"
+    android:hint="SearchManagerTest Hint"
+/>
+
diff --git a/tests/AndroidTests/run_test.sh b/tests/AndroidTests/run_test.sh
new file mode 100755
index 0000000..0cdf63f
--- /dev/null
+++ b/tests/AndroidTests/run_test.sh
@@ -0,0 +1,4 @@
+framework=/system/framework
+bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
+adb shell exec dalvikvm  -Xbootclasspath:$bpath -cp system/app/AndroidTests.apk \
+      com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AndroidPerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/AndroidPerformanceTests.java
new file mode 100644
index 0000000..b6a8594
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/AndroidPerformanceTests.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.TestListActivity;
+
+public class AndroidPerformanceTests extends TestListActivity {
+    @Override
+    public String getTestSuite() {
+        return "com.android.unit_tests.AndroidPerformanceTests$Suite";
+    }
+
+    public static class Suite {
+        public static String[] children() {
+            return new String[] {
+                DatabasePerformanceTests.class.getName(),
+                GraphicsPerformanceTests.class.getName(),
+                JavaPerformanceTests.class.getName(),
+                LogTest.PerformanceTest.class.getName(),
+                PerformanceTests.class.getName(),
+                TextViewPerformanceTest.class.getName(),
+            };
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java b/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java
new file mode 100644
index 0000000..4b86add
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/AndroidTests.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2005 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.unit_tests;
+
+import android.test.FrameworkTests;
+import android.test.suitebuilder.TestSuiteBuilder;
+
+import junit.framework.TestSuite;
+
+public class AndroidTests extends TestSuite {
+
+    public static TestSuite suite() {
+        TestSuiteBuilder suiteBuilder = new TestSuiteBuilder(AndroidTests.class);
+        TestSuite suite = suiteBuilder.includeAllPackagesUnderHere().build();
+        
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ApacheHttpTests.java b/tests/AndroidTests/src/com/android/unit_tests/ApacheHttpTests.java
new file mode 100644
index 0000000..cf759e0
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ApacheHttpTests.java
@@ -0,0 +1,13 @@
+package com.android.unit_tests;
+
+import junit.framework.TestSuite;
+
+public class ApacheHttpTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(ApacheHttpTests.class.getName());
+
+        suite.addTestSuite(TestHttpService.class);
+
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
new file mode 100755
index 0000000..3daa8ab
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/AppCacheTest.java
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.IPackageStatsObserver;
+import android.content.pm.PackageStats;
+import android.content.pm.IPackageManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.StatFs;
+
+public class AppCacheTest extends AndroidTestCase {
+    private static final boolean localLOGV = false;
+    public static final String TAG="AppCacheTest";
+    public final long MAX_WAIT_TIME=60*1000;
+    public final long WAIT_TIME_INCR=10*1000;
+    private static final int THRESHOLD=5;
+    private static final int ACTUAL_THRESHOLD=10;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if(localLOGV) Log.i(TAG, "Cleaning up cache directory first");
+        cleanUpCacheDirectory();
+    }
+    
+    void cleanUpDirectory(File pDir, String dirName) {
+       File testDir = new File(pDir,  dirName);
+       if(!testDir.exists()) {
+           return;
+       }
+        String fList[] = testDir.list();
+        for(int i = 0; i < fList.length; i++) {
+            File file = new File(testDir, fList[i]);
+            if(file.isDirectory()) {
+                cleanUpDirectory(testDir, fList[i]);
+            } else {
+                file.delete();
+            }
+        }
+        testDir.delete();
+    }
+    
+    void cleanUpCacheDirectory() {
+        File testDir = mContext.getCacheDir();
+        if(!testDir.exists()) {
+            return;
+        }
+        
+         String fList[] = testDir.list();
+         if(fList == null) {
+             testDir.delete();
+             return;
+         }
+         for(int i = 0; i < fList.length; i++) {
+             File file = new File(testDir, fList[i]);
+             if(file.isDirectory()) {
+                 cleanUpDirectory(testDir, fList[i]);
+             } else {
+                 file.delete();
+             }
+         }
+     }
+    
+    @SmallTest
+    public void testDeleteAllCacheFiles() {
+        String testName="testDeleteAllCacheFiles";
+        cleanUpCacheDirectory();
+    }
+    
+    void failStr(String errMsg) {
+        Log.w(TAG, "errMsg="+errMsg);
+        fail(errMsg);
+    }
+    void failStr(Exception e) {
+        Log.w(TAG, "e.getMessage="+e.getMessage());
+        Log.w(TAG, "e="+e);
+    }
+    long getFreeStorageBlks(StatFs st) {
+        st.restat("/data");
+        return st.getFreeBlocks();
+    }
+    
+    long getFreeStorageSize(StatFs st) {
+        st.restat("/data");
+        return (st.getFreeBlocks()*st.getBlockSize());
+    }
+    @LargeTest
+    public void testFreeApplicationCacheAllFiles() throws Exception {
+        boolean TRACKING = true;
+        StatFs st = new StatFs("/data");
+        long blks1 = getFreeStorageBlks(st);
+        long availableMem = getFreeStorageSize(st);
+        File cacheDir = mContext.getCacheDir();
+        assertNotNull(cacheDir);
+        createTestFiles1(cacheDir, "testtmpdir", 5);
+        long blks2 = getFreeStorageBlks(st);
+        if(localLOGV || TRACKING) Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
+        //this should free up the test files that were created earlier
+        invokePMFreeApplicationCache(availableMem);
+        long blks3 = getFreeStorageBlks(st);
+        if(localLOGV || TRACKING) Log.i(TAG, "blks3="+blks3);
+        verifyTestFiles1(cacheDir, "testtmpdir", 5);
+    }
+    
+    @LargeTest
+    public void testFreeApplicationCacheSomeFiles() throws Exception {
+        StatFs st = new StatFs("/data");
+        long blks1 = getFreeStorageBlks(st);
+        File cacheDir = mContext.getCacheDir();
+        assertNotNull(cacheDir);
+        createTestFiles1(cacheDir, "testtmpdir", 5);
+        long blks2 = getFreeStorageBlks(st);
+        Log.i(TAG, "blk1="+blks1+", blks2="+blks2);
+        long diff = (blks1-blks2-2);
+        assertTrue(invokePMFreeApplicationCache(diff*st.getBlockSize()));    
+        long blks3 = getFreeStorageBlks(st);
+        //blks3 should be greater than blks2 and less than blks1
+        if(!((blks3 <= blks1) && (blks3 >= blks2))) {
+            failStr("Expected "+(blks1-blks2)+" number of blocks to be freed but freed only "
+                    +(blks1-blks3));
+        }
+    }
+    
+    /**
+     * This method opens an output file writes to it, opens the same file as an input 
+     * stream, reads the contents and verifies the data that was written earlier can be read
+     */
+    public void openOutFileInAppFilesDir(File pFile, String pFileOut) {
+        FileOutputStream fos = null;
+        try {
+            fos = new FileOutputStream(pFile);
+        } catch (FileNotFoundException e1) {
+            failStr("Error when opening file "+e1);
+            return;
+        }
+        try {
+            fos.write(pFileOut.getBytes());
+            fos.close();
+        } catch (FileNotFoundException e) {
+            failStr(e.getMessage());
+        } catch (IOException e) {
+            failStr(e.getMessage());
+        } 
+        int count = pFileOut.getBytes().length;
+        byte[] buffer = new byte[count];
+        try {
+            FileInputStream fis = new FileInputStream(pFile);
+            fis.read(buffer, 0, count);
+            fis.close();
+        } catch (FileNotFoundException e) {
+            failStr("Failed when verifing output opening file "+e.getMessage());
+        } catch (IOException e) {
+            failStr("Failed when verifying output, reading from written file "+e);
+        }
+        String str = new String(buffer);
+        assertEquals(str, pFileOut);
+    } 
+    
+    /*
+     * This test case verifies that output written to a file
+     * using Context.openFileOutput has executed successfully.
+     * The operation is verified by invoking Context.openFileInput
+     */
+    @MediumTest
+    public void testAppFilesCreateFile() {
+        String fileName = "testFile1.txt";
+        String fileOut = "abcdefghijklmnopqrstuvwxyz";
+        Context con = super.getContext();
+        try {
+            FileOutputStream fos = con.openFileOutput(fileName, Context.MODE_PRIVATE);
+            fos.close();
+        } catch (FileNotFoundException e) {
+            failStr(e);
+        } catch (IOException e) {
+            failStr(e);
+        }
+    }
+    
+    @SmallTest
+    public void testAppCacheCreateFile() {
+        String fileName = "testFile1.txt";
+        String fileOut = "abcdefghijklmnopqrstuvwxyz";
+        Context con = super.getContext();
+        File file = new File(con.getCacheDir(), fileName);
+        openOutFileInAppFilesDir(file, fileOut);
+        cleanUpCacheDirectory();
+    }
+    
+    @MediumTest
+    public void testAppCreateCacheFiles() {
+        File cacheDir = mContext.getCacheDir();
+        String testDirName = "testtmp";
+        File testTmpDir = new File(cacheDir, testDirName);
+        testTmpDir.mkdir();
+        int numDirs = 3;
+        File fileArr[] = new File[numDirs];
+        for(int i = 0; i < numDirs; i++) {
+            fileArr[i] = new File(testTmpDir, "dir"+(i+1));
+            fileArr[i].mkdir();
+        }
+        byte buffer[] = getBuffer();
+        Log.i(TAG, "Size of bufer="+buffer.length);
+        for(int i = 0; i < numDirs; i++) {
+            for(int j = 1; j <= (i); j++) {
+                File file1 = new File(fileArr[i], "testFile"+j+".txt");
+                FileOutputStream fos = null;
+                try {
+                    fos = new FileOutputStream(file1);
+                    for(int k = 1; k < 10; k++) {
+                        fos.write(buffer);
+                    }
+                    Log.i(TAG, "wrote 10K bytes to "+file1);
+                    fos.close();
+                } catch (FileNotFoundException e) {
+                    Log.i(TAG, "Excetion ="+e);
+                    fail("Error when creating outputstream "+e);
+                } catch(IOException e) {
+                    Log.i(TAG, "Excetion ="+e);
+                    fail("Error when writing output "+e);
+                }
+            }
+        }
+    }
+    
+    byte[] getBuffer() {
+        String sbuffer = "a";
+        for(int i = 0; i < 10; i++) {
+            sbuffer += sbuffer;
+        }
+        return sbuffer.getBytes();
+    }
+    
+    long getFileNumBlocks(long fileSize, int blkSize) {
+        long ret = fileSize/blkSize;
+        if(ret*blkSize < fileSize) {
+            ret++;
+        }
+        return ret;
+    }
+    
+    //@LargeTest
+    public void testAppCacheClear() {
+        String dataDir="/data/data";
+        StatFs st = new StatFs(dataDir);
+        int blkSize = st.getBlockSize();
+        int totBlks = st.getBlockCount();
+        long availableBlks = st.getFreeBlocks();
+        long thresholdBlks = (totBlks*THRESHOLD)/100;
+        String testDirName = "testdir";
+        //create directory in cache
+        File testDir = new File(mContext.getCacheDir(),  testDirName);
+        testDir.mkdirs();
+        byte[] buffer = getBuffer();
+        int i = 1;
+        if(localLOGV) Log.i(TAG, "availableBlks="+availableBlks+", thresholdBlks="+thresholdBlks);
+        long createdFileBlks = 0;
+        int imax = 300;
+        while((availableBlks > thresholdBlks) &&(i < imax)) {
+            File testFile = new File(testDir, "testFile"+i+".txt");
+            if(localLOGV) Log.i(TAG, "Creating "+i+"th test file "+testFile);
+            int jmax = i;
+            i++;
+            FileOutputStream fos;
+            try {
+                fos = new FileOutputStream(testFile);
+            } catch (FileNotFoundException e) {
+                Log.i(TAG, "Failed creating test file:"+testFile);
+                continue;
+            }
+            boolean err = false;
+            for(int j = 1; j <= jmax;j++) {
+                try {
+                    fos.write(buffer);
+                } catch (IOException e) {
+                    Log.i(TAG, "Failed to write to file:"+testFile);
+                    err = true;
+                }
+            }
+            try {
+                fos.close();
+            } catch (IOException e) {
+                Log.i(TAG, "Failed closing file:"+testFile);
+            }
+            if(err) {
+                continue;
+            }
+            createdFileBlks += getFileNumBlocks(testFile.length(), blkSize);
+            st.restat(dataDir);
+            availableBlks = st.getFreeBlocks();
+        }
+        st.restat(dataDir);
+        long availableBytes = st.getFreeBlocks()*blkSize;
+        long shouldFree = (ACTUAL_THRESHOLD-THRESHOLD)*totBlks;
+        //would have run out of memory
+        //wait for some time and confirm cache is deleted
+        try {
+            Log.i(TAG, "Sleeping for 2 minutes...");
+            Thread.sleep(2*60*1000);
+        } catch (InterruptedException e) {
+            fail("Exception when sleeping "+e);
+        }
+        boolean removedFlag = false;
+        long existingFileBlks = 0;
+        for(int k = 1; k <i; k++) {
+            File testFile = new File(testDir, "testFile"+k+".txt");
+            if(!testFile.exists()) {
+                removedFlag = true;
+                if(localLOGV) Log.i(TAG, testFile+" removed");
+            }  else {
+                existingFileBlks += getFileNumBlocks(testFile.length(), blkSize);
+            }
+        }
+        if(localLOGV) Log.i(TAG, "createdFileBlks="+createdFileBlks+
+                ", existingFileBlks="+existingFileBlks);
+        long fileSize = createdFileBlks-existingFileBlks;
+        //verify fileSize number of bytes have been cleared from cache
+        if(localLOGV) Log.i(TAG, "deletedFileBlks="+fileSize+" shouldFreeBlks="+shouldFree);
+        if((fileSize > (shouldFree-blkSize) && (fileSize < (shouldFree+blkSize)))) {
+            Log.i(TAG, "passed");
+        }
+        assertTrue(removedFlag);
+    }
+    
+    //createTestFiles(new File(super.getContext().getCacheDir(), "testtmp", "dir", 3)
+    void createTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
+        byte buffer[] = getBuffer();
+        for(int i = 0; i < numTestFiles; i++) {
+            File file1 = new File(cacheDir, testFilePrefix+i+".txt");
+            FileOutputStream fos = null;
+            try {
+                fos = new FileOutputStream(file1);
+                for(int k = 1; k < 10; k++) {
+                    fos.write(buffer);
+               }
+                fos.close();
+            } catch (FileNotFoundException e) {
+                Log.i(TAG, "Exception ="+e);
+                fail("Error when creating outputstream "+e);
+            } catch(IOException e) {
+                Log.i(TAG, "Exception ="+e);
+                fail("Error when writing output "+e);
+            }
+            try {
+                //introduce sleep for 1 s to avoid common time stamps for files being created
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                fail("Exception when sleeping "+e);
+            }
+        }
+    }
+    
+    void verifyTestFiles1(File cacheDir, String testFilePrefix, int numTestFiles) {
+        for(int i = 0; i < numTestFiles; i++) {
+            File file1 = new File(cacheDir, testFilePrefix+i+".txt");
+            if(file1.exists()) {
+                fail("file:"+file1+" should not exist");
+            }
+        }
+    }
+    
+    void createTestFiles2(File cacheDir, String rootTestDirName, String subDirPrefix, int numDirs, String testFilePrefix) {
+        Context con = super.getContext();
+        File testTmpDir = new File(cacheDir, rootTestDirName);
+        testTmpDir.mkdir();
+        File fileArr[] = new File[numDirs];
+        for(int i = 0; i < numDirs; i++) {
+            fileArr[i] = new File(testTmpDir, subDirPrefix+(i+1));
+            fileArr[i].mkdir();
+        }
+        byte buffer[] = getBuffer();
+        for(int i = 0; i < numDirs; i++) {
+            for(int j = 1; j <= (i); j++) {
+                File file1 = new File(fileArr[i], testFilePrefix+j+".txt");
+                FileOutputStream fos = null;
+                try {
+                    fos = new FileOutputStream(file1);
+                    for(int k = 1; k < 10; k++) {
+                        fos.write(buffer);
+                    }
+                    fos.close();
+                } catch (FileNotFoundException e) {
+                    Log.i(TAG, "Exception ="+e);
+                    fail("Error when creating outputstream "+e);
+                } catch(IOException e) {
+                    Log.i(TAG, "Exception ="+e);
+                    fail("Error when writing output "+e);
+                }
+                try {
+                    //introduce sleep for 10 ms to avoid common time stamps for files being created
+                    Thread.sleep(10);
+                } catch (InterruptedException e) {
+                    fail("Exception when sleeping "+e);
+                }
+            }
+        }
+    }
+    
+    class PackageDataObserver extends IPackageDataObserver.Stub {
+        public boolean retValue = false;
+        private boolean doneFlag = false;
+        public void onRemoveCompleted(String packageName, boolean succeeded)
+                throws RemoteException {
+            synchronized(this) {
+                retValue = succeeded;
+                doneFlag = true;
+                notifyAll();
+            }
+        }
+        public boolean isDone() {
+            return doneFlag;
+        }
+    }
+    
+    IPackageManager getPm() {
+        return  IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+    }
+    
+    boolean invokePMDeleteAppCacheFiles() throws Exception {
+        try {
+            String packageName = mContext.getPackageName();
+            PackageDataObserver observer = new PackageDataObserver();
+            //wait on observer
+            synchronized(observer) {
+                getPm().deleteApplicationCacheFiles(packageName, observer);
+                long waitTime = 0;
+                while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
+                    observer.wait(WAIT_TIME_INCR);
+                    waitTime += WAIT_TIME_INCR;
+                }
+                if(!observer.isDone()) {
+                    throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
+                }
+            }
+            return observer.retValue;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+            return false;
+        } catch (InterruptedException e) {
+            Log.w(TAG, "InterruptedException :"+e);
+            return false;
+        }
+    }
+    
+    boolean invokePMFreeApplicationCache(long idealStorageSize) throws Exception {
+        try {
+            String packageName = mContext.getPackageName();
+            PackageDataObserver observer = new PackageDataObserver();
+            //wait on observer
+            synchronized(observer) {
+                getPm().freeStorageAndNotify(idealStorageSize, observer);
+                long waitTime = 0;
+                while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
+                    observer.wait(WAIT_TIME_INCR);
+                    waitTime += WAIT_TIME_INCR;
+                }
+                if(!observer.isDone()) {
+                    throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
+                }
+            }
+            return observer.retValue;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+            return false;
+        } catch (InterruptedException e) {
+            Log.w(TAG, "InterruptedException :"+e);
+            return false;
+        }
+    }
+
+    boolean invokePMFreeStorage(long idealStorageSize, FreeStorageReceiver r, 
+            PendingIntent pi) throws Exception {
+        try {
+            // Spin lock waiting for call back
+            synchronized(r) {
+                getPm().freeStorage(idealStorageSize, pi);
+                long waitTime = 0;
+                while(!r.isDone() && (waitTime < MAX_WAIT_TIME)) {
+                    r.wait(WAIT_TIME_INCR);
+                    waitTime += WAIT_TIME_INCR;
+                }
+                if(!r.isDone()) {
+                    throw new Exception("timed out waiting for call back from PendingIntent");
+                }
+            }
+            return r.getResultCode() == 1;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+            return false;
+        } catch (InterruptedException e) {
+            Log.w(TAG, "InterruptedException :"+e);
+            return false;
+        }
+    }
+    
+    @LargeTest
+    public void testDeleteAppCacheFiles() throws Exception {
+        String testName="testDeleteAppCacheFiles";
+        File cacheDir = mContext.getCacheDir();
+        createTestFiles1(cacheDir, "testtmpdir", 5);
+        assertTrue(invokePMDeleteAppCacheFiles());
+        //confirm files dont exist
+        verifyTestFiles1(cacheDir, "testtmpdir", 5);
+    }
+
+    class PackageStatsObserver extends IPackageStatsObserver.Stub {
+        public boolean retValue = false;
+        public PackageStats stats;
+        private boolean doneFlag = false;
+        
+        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
+                throws RemoteException {
+            synchronized(this) {
+                retValue = succeeded;
+                stats = pStats;
+                doneFlag = true;
+                notifyAll();
+            }
+        }
+        public boolean isDone() {
+            return doneFlag;
+        }
+    }
+    
+    public PackageStats invokePMGetPackageSizeInfo() throws Exception {
+        try {
+            String packageName = mContext.getPackageName();
+            PackageStatsObserver observer = new PackageStatsObserver();
+            //wait on observer
+            synchronized(observer) {
+                getPm().getPackageSizeInfo(packageName, observer);
+                long waitTime = 0;
+                while((!observer.isDone()) || (waitTime > MAX_WAIT_TIME) ) {
+                    observer.wait(WAIT_TIME_INCR);
+                    waitTime += WAIT_TIME_INCR;
+                }
+                if(!observer.isDone()) {
+                    throw new Exception("Timed out waiting for PackageStatsObserver.onGetStatsCompleted");
+                }
+            }
+            if(localLOGV) Log.i(TAG, "OBSERVER RET VALUES code="+observer.stats.codeSize+
+                    ", data="+observer.stats.dataSize+", cache="+observer.stats.cacheSize);
+            return observer.stats;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+            return null;
+        } catch (InterruptedException e) {
+            Log.w(TAG, "InterruptedException :"+e);
+            return null;
+        }
+    }
+    
+    @SmallTest
+    public void testGetPackageSizeInfo() throws Exception {
+        String testName="testGetPackageSizeInfo";
+        PackageStats stats = invokePMGetPackageSizeInfo();
+        assertTrue(stats!=null);
+        //confirm result
+        if(localLOGV) Log.i(TAG, "code="+stats.codeSize+", data="+stats.dataSize+
+                ", cache="+stats.cacheSize);
+    }
+    
+    @SmallTest
+    public void testGetSystemSharedLibraryNames() throws Exception {
+        try {
+            String[] sharedLibs = getPm().getSystemSharedLibraryNames();
+            if (localLOGV) {
+                for (String str : sharedLibs) {
+                    Log.i(TAG, str);
+                }
+            }
+        } catch (RemoteException e) {
+            fail("Failed invoking getSystemSharedLibraryNames with exception:" + e);
+        }   
+    }
+    
+    class FreeStorageReceiver extends BroadcastReceiver {
+        public static final String ACTION_FREE = "com.android.unit_tests.testcallback";
+        private boolean doneFlag = false;
+        
+        public boolean isDone() {
+            return doneFlag;
+        }
+        
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if(intent.getAction().equalsIgnoreCase(ACTION_FREE)) {
+                if (localLOGV) Log.i(TAG, "Got notification: clear cache succeeded "+getResultCode());
+                synchronized (this) {
+                    doneFlag = true;
+                    notifyAll();
+                }
+            }
+        }
+    }
+    
+    @SmallTest
+    public void testFreeStorage() throws Exception {
+        boolean TRACKING = true;
+        StatFs st = new StatFs("/data");
+        long blks1 = getFreeStorageBlks(st);
+        if(localLOGV || TRACKING) Log.i(TAG, "Available free blocks="+blks1);
+        long availableMem = getFreeStorageSize(st);
+        File cacheDir = mContext.getCacheDir();
+        assertNotNull(cacheDir);
+        createTestFiles1(cacheDir, "testtmpdir", 5);
+        long blks2 = getFreeStorageBlks(st);
+        if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after writing test files in application cache="+blks2);
+        // Create receiver and register it
+        FreeStorageReceiver receiver = new FreeStorageReceiver();
+        mContext.registerReceiver(receiver, new IntentFilter(FreeStorageReceiver.ACTION_FREE));
+        PendingIntent pi = PendingIntent.getBroadcast(mContext,
+                0,  new Intent(FreeStorageReceiver.ACTION_FREE), 0);
+        // Invoke PackageManager api
+        invokePMFreeStorage(availableMem, receiver, pi);
+        long blks3 = getFreeStorageBlks(st);
+        if(localLOGV || TRACKING) Log.i(TAG, "Available blocks after freeing cache"+blks3);
+        assertEquals(receiver.getResultCode(), 1);
+        mContext.unregisterReceiver(receiver);
+        // Verify result  
+        verifyTestFiles1(cacheDir, "testtmpdir", 5);
+    }
+    
+    /* utility method used to create observer and check async call back from PackageManager.
+     * ClearApplicationUserData
+     */
+    boolean invokePMClearApplicationUserData() throws Exception {
+        try {
+            String packageName = mContext.getPackageName();
+            PackageDataObserver observer = new PackageDataObserver();
+            //wait on observer
+            synchronized(observer) {
+                getPm().clearApplicationUserData(packageName, observer);
+                long waitTime = 0;
+                while(!observer.isDone() || (waitTime > MAX_WAIT_TIME)) {
+                    observer.wait(WAIT_TIME_INCR);
+                    waitTime += WAIT_TIME_INCR;
+                }
+                if(!observer.isDone()) {
+                    throw new Exception("timed out waiting for PackageDataObserver.onRemoveCompleted");
+                }
+            }
+            return observer.retValue;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
+            return false;
+        } catch (InterruptedException e) {
+            Log.w(TAG, "InterruptedException :"+e);
+            return false;
+        }
+    }
+    
+    void verifyUserDataCleared(File pDir) {
+        if(localLOGV) Log.i(TAG, "Verifying "+pDir);
+        if(pDir == null) {
+            return;
+        }
+        String fileList[] = pDir.list();
+        if(fileList == null) {
+            return;
+        }
+        int imax = fileList.length;
+       //look recursively in user data dir
+        for(int i = 0; i < imax; i++) {
+            if(localLOGV) Log.i(TAG, "Found entry "+fileList[i]+ "in "+pDir);
+            if("lib".equalsIgnoreCase(fileList[i])) {
+                if(localLOGV) Log.i(TAG, "Ignoring lib directory");
+                continue;
+            }
+            fail(pDir+" should be empty or contain only lib subdirectory. Found "+fileList[i]);
+        }
+    }
+    
+    File getDataDir() {
+        try {
+            ApplicationInfo appInfo = getPm().getApplicationInfo(mContext.getPackageName(), 0);
+            return new File(appInfo.dataDir);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Pacakge manager dead", e);
+        }
+    }
+    
+    @LargeTest
+    public void testClearApplicationUserDataWithTestData() throws Exception {
+        File cacheDir = mContext.getCacheDir();
+        createTestFiles1(cacheDir, "testtmpdir", 5);
+        if(localLOGV) {
+            Log.i(TAG, "Created test data Waiting for 60seconds before continuing");
+            Thread.sleep(60*1000);
+        }
+        assertTrue(invokePMClearApplicationUserData());
+        //confirm files dont exist
+        verifyUserDataCleared(getDataDir());
+    }
+    
+    @SmallTest
+    public void testClearApplicationUserDataWithNoTestData() throws Exception {
+        assertTrue(invokePMClearApplicationUserData());
+        //confirm files dont exist
+        verifyUserDataCleared(getDataDir());
+    }
+    
+    @LargeTest
+    public void testClearApplicationUserDataNoObserver() throws Exception {
+        getPm().clearApplicationUserData(mContext.getPackageName(), null);
+        //sleep for 1 minute
+        Thread.sleep(60*1000);
+        //confirm files dont exist
+        verifyUserDataCleared(getDataDir());
+    }
+    
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ArrayListTest.java b/tests/AndroidTests/src/com/android/unit_tests/ArrayListTest.java
new file mode 100644
index 0000000..81e6efd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ArrayListTest.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import java.util.ArrayList;
+import android.test.PerformanceTestBase;
+
+public class ArrayListTest extends PerformanceTestBase {
+
+    private ArrayList<Integer> mList;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mList = new ArrayList();
+        mList.add(0);
+        mList.add(1);
+        mList.add(2);
+        mList.add(3);
+        mList.add(4);
+        mList.add(5);
+        mList.add(6);
+        mList.add(7);
+        mList.add(8);
+        mList.add(9);
+    }
+
+    public void testArrayListAdd() {
+        int i = 0;
+        for (; i < 10; i++) {
+            mList.add(i);
+            mList.add(i);
+            mList.add(i);
+            mList.add(i);
+            mList.add(i);
+            mList.add(i);
+            mList.add(i);
+            mList.add(i);
+            mList.add(i);
+            mList.add(i);
+        }
+    }
+
+    public void testArrayListAdd1() {
+        int i = 0;
+        for (; i < 10; i++) {
+            mList.add(7, i);
+            mList.add(7, i);
+            mList.add(7, i);
+            mList.add(7, i);
+            mList.add(7, i);
+            mList.add(7, i);
+            mList.add(7, i);
+            mList.add(7, i);
+            mList.add(7, i);
+            mList.add(7, i);
+        }
+    }
+
+    public void testArrayListToArray() {
+        Object rArray;
+        int i = 0;
+        for (; i < 100; i++) {
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+            rArray = mList.toArray();
+        }
+    }
+
+    public void testArrayListSize() {
+        int i = 0, len;
+        for (; i < 100; i++) {
+            len = mList.size();
+            len = mList.size();
+            len = mList.size();
+            len = mList.size();
+            len = mList.size();
+            len = mList.size();
+            len = mList.size();
+            len = mList.size();
+            len = mList.size();
+            len = mList.size();
+        }
+    }
+
+    public void testArrayListGet() {
+        int i = 0, value;
+        int len = mList.size();
+        for (; i < len; i++) {
+            value = mList.get(i);
+            value = mList.get(i);
+            value = mList.get(i);
+            value = mList.get(i);
+            value = mList.get(i);
+            value = mList.get(i);
+            value = mList.get(i);
+            value = mList.get(i);
+            value = mList.get(i);
+            value = mList.get(i);
+        }
+    }
+
+    public void testArrayListContains() {
+        boolean flag;
+        int i = 0;
+
+        for (; i < 100; i++) {
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+            flag = mList.contains(i);
+
+        }
+    }
+
+    public void testArrayListToArray1() {
+        Integer[] rArray = new Integer[10];
+
+        Integer[] mArray;
+        int i = 0;
+        for (; i < 100; i++) {
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+            mArray = mList.toArray(rArray);
+        }
+    }
+
+    public void testArrayListSet() {
+        int i = 0;
+        for (; i < 10; i++) {
+            mList.set(5, 0);
+            mList.set(5, 0);
+            mList.set(5, 0);
+            mList.set(5, 0);
+            mList.set(5, 0);
+            mList.set(5, 0);
+            mList.set(5, 0);
+            mList.set(5, 0);
+            mList.set(5, 0);
+            mList.set(5, 0);
+        }
+    }
+
+    public void testArrayListIndexOf() {
+        int i = 0, index;
+
+        for (; i < 100; i++) {
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+            index = mList.indexOf(0);
+        }
+    }
+
+    public void testArrayListLastIndexOf() {
+        int i = 0, index;
+
+        for (; i < 100; i++) {
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+            index = mList.lastIndexOf(0);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testArrayListRemove() {
+        ArrayList<Integer> aList;
+        aList = new ArrayList();
+        for (int j = 0; j < 10000; j++) {
+            aList.add(0);
+        }
+
+        int i = 0, index;
+
+        for (; i < 10; i++) {
+            index = aList.remove(0);
+            index = aList.remove(0);
+            index = aList.remove(0);
+            index = aList.remove(0);
+            index = aList.remove(0);
+            index = aList.remove(0);
+            index = aList.remove(0);
+            index = aList.remove(0);
+            index = aList.remove(0);
+            index = aList.remove(0);
+
+
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testArrayListAddAll() {
+        ArrayList<Integer> aList = new ArrayList();
+
+        int i = 0;
+        boolean b;
+        for (; i < 10; i++) {
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+            b = aList.addAll(mList);
+
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testArrayListRemove1() {
+        ArrayList<String> aList;
+        String s;
+
+        aList = new ArrayList();
+        for (int j = 0; j < 100; j++) {
+            aList.add("a");
+            aList.add("b");
+        }
+        s = new String("a");
+
+        int i = 0;
+        boolean b;
+        for (; i < 10; i++) {
+            b = aList.remove(s);
+            b = aList.remove(s);
+            b = aList.remove(s);
+            b = aList.remove(s);
+            b = aList.remove(s);
+            b = aList.remove(s);
+            b = aList.remove(s);
+            b = aList.remove(s);
+            b = aList.remove(s);
+            b = aList.remove(s);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testArrayListAddAll1() {
+        ArrayList<Integer> aList = new ArrayList();
+
+        int i = 0;
+        boolean b;
+
+        for (; i < 10; i++) {
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+            b = aList.addAll(0, mList);
+        }
+    }
+
+    public void testArrayListClone() {
+        Object rObj;
+        int i = 0;
+
+        for (; i < 100; i++) {
+            rObj = mList.clone();
+            rObj = mList.clone();
+            rObj = mList.clone();
+            rObj = mList.clone();
+            rObj = mList.clone();
+            rObj = mList.clone();
+            rObj = mList.clone();
+            rObj = mList.clone();
+            rObj = mList.clone();
+            rObj = mList.clone();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/BrickDeniedTest.java b/tests/AndroidTests/src/com/android/unit_tests/BrickDeniedTest.java
new file mode 100644
index 0000000..0f2b23b
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/BrickDeniedTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.content.Intent;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/** Test to make sure brick intents <b>don't</b> work without permission. */
+public class BrickDeniedTest extends AndroidTestCase {
+    @MediumTest
+    public void testBrick() {
+        // Try both the old and new brick intent names.  Neither should work,
+        // since this test application doesn't have the required permission.
+        // If it does work, well, the test certainly won't pass.
+        getContext().sendBroadcast(new Intent("SHES_A_BRICK_HOUSE"));
+        getContext().sendBroadcast(new Intent("android.intent.action.BRICK"));
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java b/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java
new file mode 100644
index 0000000..dbfd0e7
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/BuildTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.os.Build;
+import android.server.data.BuildData;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+/**
+ * Provides test cases for android.os.Build and android.server.data.BuildData,
+ * and, in turn, many of the system properties set by the build system.
+ */
+public class BuildTest extends TestCase {
+
+    private static final String TAG = "BuildTest";
+
+    /**
+     * Asserts that a String is non-null and non-empty.  If it is not,
+     * an AssertionFailedError is thrown with the given message.
+     */
+    private static void assertNotEmpty(String message, String string) {
+        //Log.i(TAG, "" + message + ": " + string);
+        assertNotNull(message, string);
+        assertFalse(message, string.equals(""));
+    }
+
+    /**
+     * Asserts that a String is non-null and non-empty.  If it is not,
+     * an AssertionFailedError is thrown.
+     */
+    private static void assertNotEmpty(String string) {
+        assertNotEmpty(null, string);
+    }
+
+    /**
+     * Asserts that all android.os.Build fields are non-empty and/or in a valid range.
+     */
+    @SmallTest
+    public void testBuildFields() throws Exception {
+        assertNotEmpty("ID", Build.ID);
+        assertNotEmpty("DISPLAY", Build.DISPLAY);
+        assertNotEmpty("PRODUCT", Build.PRODUCT);
+        assertNotEmpty("DEVICE", Build.DEVICE);
+        assertNotEmpty("BOARD", Build.BOARD);
+        assertNotEmpty("BRAND", Build.BRAND);
+        assertNotEmpty("MODEL", Build.MODEL);
+        assertNotEmpty("VERSION.INCREMENTAL", Build.VERSION.INCREMENTAL);
+        assertNotEmpty("VERSION.RELEASE", Build.VERSION.RELEASE);
+        assertNotEmpty("TYPE", Build.TYPE);
+        Assert.assertNotNull("TAGS", Build.TAGS); // TAGS is allowed to be empty.
+        assertNotEmpty("FINGERPRINT", Build.FINGERPRINT);
+        Assert.assertTrue("TIME", Build.TIME > 0);
+        assertNotEmpty("USER", Build.USER);
+        assertNotEmpty("HOST", Build.HOST);
+
+        // TODO: if any of the android.os.Build fields have additional constraints
+        // (e.g., must be a C identifier, must be a valid filename, must not contain any spaces)
+        // add tests for them.
+    }
+
+    /**
+     * Asserts that android.server.data.BuildData behaves as expected.
+     */
+    @SmallTest
+    public void testBuildData() throws Exception {
+        BuildData bd;
+
+        /*
+         * Default constructor
+         */
+        bd = new BuildData();
+        assertNotEmpty(bd.getFingerprint());
+        assertNotEmpty(bd.getIncrementalVersion());
+        Assert.assertTrue(bd.getTime() > 0);
+
+        /*
+         * Explicit constructor
+         */
+        final String FINGERPRINT = "fingerprint";
+        final String INCREMENTAL_VERSION = "74321";  // a valid long, for the serialization test
+        final long TIME = 12345;
+        bd = new BuildData(FINGERPRINT, INCREMENTAL_VERSION, TIME);
+        Assert.assertEquals(FINGERPRINT, bd.getFingerprint());
+        Assert.assertEquals(INCREMENTAL_VERSION, bd.getIncrementalVersion());
+        Assert.assertTrue(bd.getTime() == TIME);
+
+// The serialization methods are package-private.
+//
+// import java.io.ByteArrayInputStream;
+// import java.io.ByteArrayOutputStream;
+// import java.io.DataInputStream;
+// import java.io.DataOutputStream;
+//
+//        /*
+//         * Serialization
+//         */
+//        ByteArrayOutputStream out = new ByteArrayOutputStream();
+//        bd.write(new DataOutputStream(out));
+//        Assert.assertTrue(out.size() > 0);
+//
+//        /*
+//         * Deserialization
+//         *
+//         * The current version of BuildData converts the incremental version to
+//         * and from a long when serializing/deserializing.  Future versions should
+//         * treat it as a string.
+//         */
+//        BuildData bd2 =
+//                new BuildData(new DataInputStream(new ByteArrayInputStream(out.toByteArray())));
+//        Assert.assertEquals(bd.getFingerprint(), bd2.getFingerprint());
+//        Assert.assertEquals(bd.getIncrementalVersion(), bd2.getIncrementalVersion());
+//        Assert.assertTrue(bd.getTime() == bd2.getTime());
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CharSequencesTest.java b/tests/AndroidTests/src/com/android/unit_tests/CharSequencesTest.java
new file mode 100644
index 0000000..092f309
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/CharSequencesTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import com.android.internal.util.CharSequences;
+import static com.android.internal.util.CharSequences.forAsciiBytes;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class CharSequencesTest extends TestCase {
+
+    @SmallTest
+    public void testCharSequences() {
+        String s = "Crazy Bob";
+        byte[] bytes = s.getBytes();
+
+        String copy = toString(forAsciiBytes(bytes));
+        assertTrue(s.equals(copy));
+
+        copy = toString(forAsciiBytes(bytes, 0, s.length()));
+        assertTrue(s.equals(copy));
+
+        String crazy = toString(forAsciiBytes(bytes, 0, 5));
+        assertTrue("Crazy".equals(crazy));
+
+        String a = toString(forAsciiBytes(bytes, 0, 3).subSequence(2, 3));
+        assertTrue("a".equals(a));
+
+        String empty = toString(forAsciiBytes(bytes, 0, 3).subSequence(3, 3));
+        assertTrue("".equals(empty));
+
+        assertTrue(CharSequences.equals("bob", "bob"));
+        assertFalse(CharSequences.equals("b", "bob"));
+        assertFalse(CharSequences.equals("", "bob"));
+    }
+
+    /**
+     * Converts a CharSequence to a string the slow way. Useful for testing
+     * a CharSequence implementation.
+     */
+    static String toString(CharSequence charSequence) {
+        return new StringBuilder().append(charSequence).toString();
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ComponentTest.java b/tests/AndroidTests/src/com/android/unit_tests/ComponentTest.java
new file mode 100644
index 0000000..08fe742
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ComponentTest.java
@@ -0,0 +1,738 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import com.android.unit_tests.enabled_app.DisabledActivity;
+import com.android.unit_tests.enabled_app.DisabledProvider;
+import com.android.unit_tests.enabled_app.DisabledReceiver;
+import com.android.unit_tests.enabled_app.DisabledService;
+import com.android.unit_tests.enabled_app.EnabledActivity;
+import com.android.unit_tests.enabled_app.EnabledProvider;
+import com.android.unit_tests.enabled_app.EnabledReceiver;
+import com.android.unit_tests.enabled_app.EnabledService;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.GET_DISABLED_COMPONENTS;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Tests for disabling and enabling application components.
+ *
+ * Note: These tests are on the slow side.  This is probably because most of the tests trigger the
+ * package settings file to get written out by the PackageManagerService.  Better, more unit-y test
+ * would fix this.
+ */
+
+public class ComponentTest extends AndroidTestCase {
+
+    private PackageManager mPackageManager;
+    private Intent mDisabledActivityIntent;
+    private Intent mEnabledActivityIntent;
+    private Intent mDisabledServiceIntent;
+    private Intent mEnabledServiceIntent;
+    private Intent mDisabledReceiverIntent;
+    private Intent mEnabledReceiverIntent;
+    private Intent mDisabledAppEnabledActivityIntent;
+
+    private static final String ENABLED_PACKAGENAME =
+            "com.android.unit_tests.enabled_app";
+    private static final String DISABLED_PACKAGENAME =
+            "com.android.unit_tests.disabled_app";
+    private static final String DISABLED_ACTIVITY_CLASSNAME =
+            DisabledActivity.class.getName();
+    private static final ComponentName DISABLED_ACTIVITY_COMPONENTNAME =
+            new ComponentName(ENABLED_PACKAGENAME, DISABLED_ACTIVITY_CLASSNAME);
+    private static final String ENABLED_ACTIVITY_CLASSNAME =
+            EnabledActivity.class.getName();
+    private static final ComponentName ENABLED_ACTIVITY_COMPONENTNAME =
+            new ComponentName(ENABLED_PACKAGENAME, ENABLED_ACTIVITY_CLASSNAME);
+    private static final String DISABLED_SERVICE_CLASSNAME =
+            DisabledService.class.getName();
+    private static final ComponentName DISABLED_SERVICE_COMPONENTNAME =
+            new ComponentName(ENABLED_PACKAGENAME, DISABLED_SERVICE_CLASSNAME);
+    private static final String DISABLED_PROVIDER_CLASSNAME =
+            DisabledProvider.class.getName();
+    private static final ComponentName DISABLED_PROVIDER_COMPONENTNAME =
+            new ComponentName(ENABLED_PACKAGENAME, DISABLED_PROVIDER_CLASSNAME);
+    private static final String DISABLED_PROVIDER_NAME = DisabledProvider.class.getName();
+    private static final String ENABLED_SERVICE_CLASSNAME =
+            EnabledService.class.getName();
+    private static final ComponentName ENABLED_SERVICE_COMPONENTNAME =
+            new ComponentName(ENABLED_PACKAGENAME, ENABLED_SERVICE_CLASSNAME);
+    private static final String DISABLED_RECEIVER_CLASSNAME =
+            DisabledReceiver.class.getName();
+    private static final ComponentName DISABLED_RECEIVER_COMPONENTNAME =
+            new ComponentName(ENABLED_PACKAGENAME, DISABLED_RECEIVER_CLASSNAME);
+    private static final String ENABLED_RECEIVER_CLASSNAME =
+            EnabledReceiver.class.getName();
+    private static final ComponentName ENABLED_RECEIVER_COMPONENTNAME =
+            new ComponentName(ENABLED_PACKAGENAME, ENABLED_RECEIVER_CLASSNAME);
+    private static final String ENABLED_PROVIDER_CLASSNAME =
+            EnabledProvider.class.getName();
+    private static final ComponentName ENABLED_PROVIDER_COMPONENTNAME =
+            new ComponentName(ENABLED_PACKAGENAME, ENABLED_PROVIDER_CLASSNAME);
+    private static final String ENABLED_PROVIDER_NAME = EnabledProvider.class.getName();
+    private static final String DISABLED_APP_ENABLED_ACTIVITY_CLASSNAME =
+            com.android.unit_tests.disabled_app.EnabledActivity.class.getName();
+    private static final ComponentName DISABLED_APP_ENABLED_ACTIVITY_COMPONENTNAME =
+            new ComponentName(DISABLED_PACKAGENAME, DISABLED_APP_ENABLED_ACTIVITY_CLASSNAME);
+    private static final String TEST_CATEGORY =
+            "com.android.unit_tests.enabled_app.TEST_CATEGORY";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mPackageManager = mContext.getPackageManager();
+        mDisabledActivityIntent = new Intent();
+        mDisabledActivityIntent.setComponent(DISABLED_ACTIVITY_COMPONENTNAME);
+        mEnabledActivityIntent = new Intent();
+        mEnabledActivityIntent.setComponent(ENABLED_ACTIVITY_COMPONENTNAME);
+        mDisabledServiceIntent = new Intent();
+        mDisabledServiceIntent.setComponent(DISABLED_SERVICE_COMPONENTNAME);
+        mEnabledServiceIntent = new Intent();
+        mEnabledServiceIntent.setComponent(ENABLED_SERVICE_COMPONENTNAME);
+        mDisabledReceiverIntent = new Intent("android.intent.action.ENABLED_APP_DISABLED_RECEIVER");
+        mDisabledReceiverIntent.setComponent(DISABLED_RECEIVER_COMPONENTNAME);
+        mEnabledReceiverIntent = new Intent("android.intent.action.ENABLED_APP_ENABLED_RECEIVER");
+        mEnabledReceiverIntent.setComponent(ENABLED_RECEIVER_COMPONENTNAME);
+        mDisabledAppEnabledActivityIntent = new Intent();
+        mDisabledAppEnabledActivityIntent.setComponent(DISABLED_APP_ENABLED_ACTIVITY_COMPONENTNAME);
+    }
+
+    @SmallTest
+    public void testContextNotNull() throws Exception {
+        assertNotNull(mContext);
+    }
+
+    @MediumTest
+    public void testResolveDisabledActivity() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveActivity(mDisabledActivityIntent, 0);
+        assertNull(info);
+
+        final ResolveInfo info2 = mPackageManager.resolveActivity(
+                mDisabledActivityIntent, GET_DISABLED_COMPONENTS);
+        assertNotNull(info2);
+        assertNotNull(info2.activityInfo);
+        assertFalse(info2.activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testResolveEnabledActivity() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveActivity(mEnabledActivityIntent, 0);
+        assertNotNull(info);
+        assertNotNull(info);
+        assertNotNull(info.activityInfo);
+        assertTrue(info.activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testQueryDisabledActivity() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final List<ResolveInfo> infoList =
+                mPackageManager.queryIntentActivities(mDisabledActivityIntent, 0);
+        assertEquals(0, infoList.size());
+
+        final List<ResolveInfo> infoList2 =
+                mPackageManager.queryIntentActivities(mDisabledActivityIntent,
+                                                      GET_DISABLED_COMPONENTS);
+        assertEquals(1, infoList2.size());
+        final ResolveInfo info = infoList2.get(0);
+        assertNotNull(info);
+        assertNotNull(info.activityInfo);
+        assertFalse(info.activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testQueryEnabledActivity() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final List<ResolveInfo> infoList =
+                mPackageManager.queryIntentActivities(mEnabledActivityIntent, 0);
+        assertEquals(1, infoList.size());
+        final ResolveInfo info = infoList.get(0);
+        assertNotNull(info);
+        assertNotNull(info.activityInfo);
+        assertTrue(info.activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testGetDisabledActivityInfo() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        try {
+            mPackageManager.getActivityInfo(DISABLED_ACTIVITY_COMPONENTNAME, 0);
+            fail("Attempt to get info on disabled component should fail.");
+        } catch (PackageManager.NameNotFoundException e) {
+            // expected
+        }
+
+        final ActivityInfo activityInfo =
+              mPackageManager.getActivityInfo(DISABLED_ACTIVITY_COMPONENTNAME,
+                                              GET_DISABLED_COMPONENTS);
+        assertNotNull(activityInfo);
+        assertFalse(activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testGetEnabledActivityInfo() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        ActivityInfo activityInfo =
+              mPackageManager.getActivityInfo(ENABLED_ACTIVITY_COMPONENTNAME, 0);
+        assertNotNull(activityInfo);
+        assertTrue(activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testEnableActivity() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveActivity(mDisabledActivityIntent, 0);
+        assertNull(info);
+        mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_ENABLED,
+                                                   PackageManager.DONT_KILL_APP);
+        final ResolveInfo info2 =
+                mPackageManager.resolveActivity(mDisabledActivityIntent,
+                                                0);
+        assertNotNull(info2);
+        assertNotNull(info2.activityInfo);
+        assertFalse(info2.activityInfo.enabled);
+
+        final List<ResolveInfo> infoList =
+                mPackageManager.queryIntentActivities(mDisabledActivityIntent, 0);
+        assertEquals(1, infoList.size());
+    }
+
+    @LargeTest
+    public void testDisableActivity() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveActivity(mEnabledActivityIntent, 0);
+        assertNotNull(info);
+        assertNotNull(info.activityInfo);
+        mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DISABLED,
+                                                   PackageManager.DONT_KILL_APP);
+        final ResolveInfo info2 =
+                mPackageManager.resolveActivity(mEnabledActivityIntent,
+                                                0);
+        assertNull(info2);
+
+        final ResolveInfo info3 = mPackageManager.resolveActivity(mEnabledActivityIntent,
+                                                                  GET_DISABLED_COMPONENTS);
+        assertNotNull(info3);
+        assertNotNull(info3.activityInfo);
+        assertTrue(info3.activityInfo.enabled);
+
+        final List<ResolveInfo> infoList =
+                mPackageManager.queryIntentActivities(mEnabledActivityIntent, 0);
+        assertEquals(0, infoList.size());
+    }
+
+    @MediumTest
+    public void testResolveDisabledService() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveService(mDisabledServiceIntent, 0);
+        assertNull(info);
+
+        final ResolveInfo info2 = mPackageManager.resolveService(
+                mDisabledServiceIntent, GET_DISABLED_COMPONENTS);
+        assertNotNull(info2);
+        assertNotNull(info2.serviceInfo);
+        assertFalse(info2.serviceInfo.enabled);
+    }
+
+    @MediumTest
+    public void testResolveEnabledService() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveService(mEnabledServiceIntent, 0);
+        assertNotNull(info);
+        assertNotNull(info);
+        assertNotNull(info.serviceInfo);
+        assertTrue(info.serviceInfo.enabled);
+    }
+
+    @MediumTest
+    public void testQueryDisabledService() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final List<ResolveInfo> infoList =
+                mPackageManager.queryIntentServices(mDisabledServiceIntent, 0);
+        assertEquals(0, infoList.size());
+
+        final List<ResolveInfo> infoList2 =
+                mPackageManager.queryIntentServices(mDisabledServiceIntent,
+                                                      GET_DISABLED_COMPONENTS);
+        assertEquals(1, infoList2.size());
+        final ResolveInfo info = infoList2.get(0);
+        assertNotNull(info);
+        assertNotNull(info.serviceInfo);
+        assertFalse(info.serviceInfo.enabled);
+    }
+
+    @MediumTest
+    public void testQueryEnabledService() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final List<ResolveInfo> infoList =
+                mPackageManager.queryIntentServices(mEnabledServiceIntent, 0);
+        assertEquals(1, infoList.size());
+        final ResolveInfo info = infoList.get(0);
+        assertNotNull(info);
+        assertNotNull(info.serviceInfo);
+        assertTrue(info.serviceInfo.enabled);
+    }
+
+    @MediumTest
+    public void testGetDisabledServiceInfo() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        try {
+            mPackageManager.getServiceInfo(DISABLED_SERVICE_COMPONENTNAME, 0);
+            fail("Attempt to get info on disabled component should fail.");
+        } catch (PackageManager.NameNotFoundException e) {
+            // expected
+        }
+
+        final ServiceInfo serviceInfo =
+              mPackageManager.getServiceInfo(DISABLED_SERVICE_COMPONENTNAME,
+                                              GET_DISABLED_COMPONENTS);
+        assertNotNull(serviceInfo);
+        assertFalse(serviceInfo.enabled);
+    }
+
+    @MediumTest
+    public void testGetEnabledServiceInfo() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        ServiceInfo serviceInfo =
+              mPackageManager.getServiceInfo(ENABLED_SERVICE_COMPONENTNAME, 0);
+        assertNotNull(serviceInfo);
+        assertTrue(serviceInfo.enabled);
+    }
+
+    @MediumTest
+    public void testEnableService() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveService(mDisabledServiceIntent, 0);
+        assertNull(info);
+        mPackageManager.setComponentEnabledSetting(DISABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_ENABLED,
+                                                   PackageManager.DONT_KILL_APP);
+        final ResolveInfo info2 =
+                mPackageManager.resolveService(mDisabledServiceIntent,
+                                                0);
+        assertNotNull(info2);
+        assertNotNull(info2.serviceInfo);
+        assertFalse(info2.serviceInfo.enabled);
+    }
+
+    @LargeTest
+    public void testDisableService() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveService(mEnabledServiceIntent, 0);
+        assertNotNull(info);
+        assertNotNull(info.serviceInfo);
+        mPackageManager.setComponentEnabledSetting(ENABLED_SERVICE_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DISABLED,
+                                                   PackageManager.DONT_KILL_APP);
+        final ResolveInfo info2 =
+                mPackageManager.resolveService(mEnabledServiceIntent,
+                                                0);
+        assertNull(info2);
+
+        final ResolveInfo info3 = mPackageManager.resolveService(mEnabledServiceIntent,
+                                                                  GET_DISABLED_COMPONENTS);
+        assertNotNull(info3);
+        assertNotNull(info3.serviceInfo);
+        assertTrue(info3.serviceInfo.enabled);
+    }
+
+    @MediumTest
+    public void testQueryDisabledReceiver() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final List<ResolveInfo> infoList =
+                mPackageManager.queryBroadcastReceivers(mDisabledReceiverIntent, 0);
+        assertEquals(0, infoList.size());
+
+        final List<ResolveInfo> infoList2 =
+                mPackageManager.queryBroadcastReceivers(mDisabledReceiverIntent,
+                                                      GET_DISABLED_COMPONENTS);
+        assertEquals(1, infoList2.size());
+        final ResolveInfo info = infoList2.get(0);
+        assertNotNull(info);
+        assertNotNull(info.activityInfo);
+        assertFalse(info.activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testQueryEnabledReceiver() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_RECEIVER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final List<ResolveInfo> infoList =
+                mPackageManager.queryBroadcastReceivers(mEnabledReceiverIntent, 0);
+        assertEquals(1, infoList.size());
+        final ResolveInfo info = infoList.get(0);
+        assertNotNull(info);
+        assertNotNull(info.activityInfo);
+        assertTrue(info.activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testGetDisabledReceiverInfo() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        try {
+            mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, 0);
+            fail("Attempt to get info on disabled component should fail.");
+        } catch (PackageManager.NameNotFoundException e) {
+            // expected
+        }
+
+        final ActivityInfo activityInfo =
+              mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME,
+                                              GET_DISABLED_COMPONENTS);
+        assertNotNull(activityInfo);
+        assertFalse(activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testGetEnabledReceiverInfo() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_RECEIVER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        ActivityInfo activityInfo =
+              mPackageManager.getReceiverInfo(ENABLED_RECEIVER_COMPONENTNAME, 0);
+        assertNotNull(activityInfo);
+        assertTrue(activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testEnableReceiver() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        try {
+            mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, 0);
+            fail("Attempt to get info on disabled component should fail.");
+        } catch (PackageManager.NameNotFoundException e) {
+            // expected
+        }
+
+        mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_ENABLED,
+                                                   PackageManager.DONT_KILL_APP);
+        ActivityInfo activityInfo =
+              mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, 0);
+        assertNotNull(activityInfo);
+        assertFalse(activityInfo.enabled);
+    }
+
+    @MediumTest
+    public void testDisableReceiver() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_RECEIVER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        ActivityInfo activityInfo =
+              mPackageManager.getReceiverInfo(ENABLED_RECEIVER_COMPONENTNAME, 0);
+        assertNotNull(activityInfo);
+        assertTrue(activityInfo.enabled);
+        mPackageManager.setComponentEnabledSetting(DISABLED_RECEIVER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DISABLED,
+                                                   PackageManager.DONT_KILL_APP);
+        try {
+            mPackageManager.getReceiverInfo(DISABLED_RECEIVER_COMPONENTNAME, 0);
+            fail("Attempt to get info on disabled component should fail.");
+        } catch (PackageManager.NameNotFoundException e) {
+            // expected
+        }
+    }
+
+    @MediumTest
+    public void testResolveEnabledProvider() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_PROVIDER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        ProviderInfo providerInfo =
+                mPackageManager.resolveContentProvider(ENABLED_PROVIDER_NAME, 0);
+        assertNotNull(providerInfo);
+        assertTrue(providerInfo.enabled);
+    }
+
+    @MediumTest
+    public void testResolveDisabledProvider() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_PROVIDER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        ProviderInfo providerInfo =
+                mPackageManager.resolveContentProvider(DISABLED_PROVIDER_NAME, 0);
+        assertNull(providerInfo);
+        ProviderInfo providerInfo2 =
+                mPackageManager.resolveContentProvider(DISABLED_PROVIDER_NAME,
+                                                       GET_DISABLED_COMPONENTS);
+        assertNotNull(providerInfo2);
+        assertFalse(providerInfo2.enabled);
+    }
+
+    @MediumTest
+    public void testEnableProvider() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_PROVIDER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+        ProviderInfo providerInfo =
+                mPackageManager.resolveContentProvider(DISABLED_PROVIDER_NAME, 0);
+        assertNull(providerInfo);
+
+        mPackageManager.setComponentEnabledSetting(DISABLED_PROVIDER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_ENABLED,
+                                                   PackageManager.DONT_KILL_APP);
+        ProviderInfo providerInfo2 =
+                mPackageManager.resolveContentProvider(DISABLED_PROVIDER_NAME, 0);
+        assertNotNull(providerInfo2);
+        assertFalse(providerInfo2.enabled);
+    }
+
+    @MediumTest
+    public void testDisableProvider() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_PROVIDER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+        ProviderInfo providerInfo =
+                mPackageManager.resolveContentProvider(ENABLED_PROVIDER_NAME, 0);
+        assertNotNull(providerInfo);
+        assertTrue(providerInfo.enabled);
+
+        mPackageManager.setComponentEnabledSetting(ENABLED_PROVIDER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DISABLED,
+                                                   PackageManager.DONT_KILL_APP);
+        ProviderInfo providerInfo2 =
+                mPackageManager.resolveContentProvider(ENABLED_PROVIDER_NAME, 0);
+        assertNull(providerInfo2);
+    }
+
+    @MediumTest
+    public void testQueryEnabledProvider() throws Exception {
+        mPackageManager.setComponentEnabledSetting(ENABLED_PROVIDER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        String enabledProviderProcessName = getComponentProcessName(ENABLED_PROVIDER_NAME);
+        PackageInfo pi = mPackageManager.getPackageInfo(ENABLED_PACKAGENAME, 0);
+        List<ProviderInfo> providerInfoList =
+                mPackageManager.queryContentProviders(enabledProviderProcessName,
+                        pi.applicationInfo.uid, 0);
+        assertNotNull(providerInfoList);
+        assertEquals(1, providerInfoList.size());
+        assertEquals(ENABLED_PROVIDER_CLASSNAME,
+                     providerInfoList.get(0).name);
+    }
+
+    @MediumTest
+    public void testQueryDisabledProvider() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_PROVIDER_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        PackageInfo pi = mPackageManager.getPackageInfo(ENABLED_PACKAGENAME, 0);
+        
+        String disabledProviderProcessName = getComponentProcessName(DISABLED_PROVIDER_NAME);
+        List<ProviderInfo> providerInfoList =
+                mPackageManager.queryContentProviders(disabledProviderProcessName,
+                        pi.applicationInfo.uid, 0);
+        assertNull(providerInfoList);
+
+
+        List<ProviderInfo> providerInfoList2 =
+                mPackageManager.queryContentProviders(disabledProviderProcessName,
+                        pi.applicationInfo.uid, GET_DISABLED_COMPONENTS);
+        assertNotNull(providerInfoList2);
+        assertEquals(1, providerInfoList2.size());
+        assertEquals(DISABLED_PROVIDER_CLASSNAME,
+                     providerInfoList2.get(0).name);
+    }
+
+    private String getComponentProcessName(String componentNameStr) {
+        ComponentInfo providerInfo =
+                mPackageManager.resolveContentProvider(componentNameStr,
+                                                       GET_DISABLED_COMPONENTS);
+        return providerInfo.processName;
+    }
+
+    public void DISABLED_testResolveEnabledActivityInDisabledApp() throws Exception {
+        mPackageManager.setApplicationEnabledSetting(DISABLED_PACKAGENAME,
+                                                     COMPONENT_ENABLED_STATE_DEFAULT,
+                                                     0);
+        mPackageManager.setComponentEnabledSetting(DISABLED_APP_ENABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info =
+                mPackageManager.resolveActivity(mDisabledAppEnabledActivityIntent, 0);
+        assertNull(info);
+
+        final ResolveInfo info2 = mPackageManager.resolveActivity(
+                mDisabledAppEnabledActivityIntent, GET_DISABLED_COMPONENTS);
+        assertNotNull(info2);
+        assertNotNull(info2.activityInfo);
+        assertTrue(info2.activityInfo.enabled);
+    }
+
+    public void DISABLED_testEnableApplication() throws Exception {
+        mPackageManager.setApplicationEnabledSetting(DISABLED_PACKAGENAME,
+                                                     COMPONENT_ENABLED_STATE_DEFAULT,
+                                                     0);
+        mPackageManager.setComponentEnabledSetting(DISABLED_APP_ENABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info =
+                mPackageManager.resolveActivity(mDisabledAppEnabledActivityIntent, 0);
+        assertNull(info);
+
+        mPackageManager.setApplicationEnabledSetting(DISABLED_PACKAGENAME,
+                                                     COMPONENT_ENABLED_STATE_ENABLED,
+                                                     0);
+        final ResolveInfo info2 = mPackageManager.resolveActivity(
+                mDisabledAppEnabledActivityIntent, 0);
+        assertNotNull(info2);
+        assertNotNull(info2.activityInfo);
+        assertTrue(info2.activityInfo.enabled);
+
+    }
+
+    public void DISABLED_testDisableApplication() throws Exception {
+        mPackageManager.setApplicationEnabledSetting(ENABLED_PACKAGENAME,
+                                                     COMPONENT_ENABLED_STATE_DEFAULT,
+                                                     0);
+        mPackageManager.setComponentEnabledSetting(ENABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final ResolveInfo info = mPackageManager.resolveActivity(mEnabledActivityIntent, 0);
+        assertNotNull(info);
+        assertNotNull(info.activityInfo);
+        assertTrue(info.activityInfo.enabled);
+
+        mPackageManager.setApplicationEnabledSetting(ENABLED_PACKAGENAME,
+                                                     COMPONENT_ENABLED_STATE_DISABLED,
+                                                     0);
+        final ResolveInfo info2 = mPackageManager.resolveActivity(mEnabledActivityIntent, 0);
+        assertNull(info2);
+
+        // Clean up
+        mPackageManager.setApplicationEnabledSetting(ENABLED_PACKAGENAME,
+                                                     COMPONENT_ENABLED_STATE_DEFAULT,
+                                                     0);
+
+    }
+
+    @MediumTest
+    public void testNonExplicitResolveAfterEnabling() throws Exception {
+        mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_DEFAULT,
+                                                   PackageManager.DONT_KILL_APP);
+
+        Intent intent = new Intent(Intent.ACTION_MAIN, null);
+        intent.addCategory(TEST_CATEGORY);
+
+        final List<ResolveInfo> launchables =
+                mPackageManager.queryIntentActivities(intent, 0);
+
+        int numItems = launchables.size();
+        assertEquals(0, numItems);
+
+        mPackageManager.setComponentEnabledSetting(DISABLED_ACTIVITY_COMPONENTNAME,
+                                                   COMPONENT_ENABLED_STATE_ENABLED,
+                                                   PackageManager.DONT_KILL_APP);
+
+        final List<ResolveInfo> launchables2 =
+                mPackageManager.queryIntentActivities(intent, 0);
+
+        int numItems2 = launchables2.size();
+        assertEquals(1, numItems2);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ContentQueryMapTest.java b/tests/AndroidTests/src/com/android/unit_tests/ContentQueryMapTest.java
new file mode 100644
index 0000000..241a1bf
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ContentQueryMapTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.content.ContentQueryMap;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import java.util.Observable;
+import java.util.Observer;
+
+/** Test of {@link ContentQueryMap} */
+public class ContentQueryMapTest extends AndroidTestCase {
+    /** Helper class to run test code in a new thread with a Looper. */
+    private abstract class LooperThread extends Thread {
+        public Throwable mError = null;
+        public boolean mSuccess = false;
+
+        abstract void go();
+
+        public void run() {
+            try {
+                Looper.prepare();
+                go();
+                Looper.loop();
+            } catch (Throwable e) {
+                mError = e;
+            }
+        }
+    }
+
+    @MediumTest
+    public void testContentQueryMap() throws Throwable {
+        LooperThread thread = new LooperThread() {
+            void go() {
+                ContentResolver r = getContext().getContentResolver();
+                Settings.System.putString(r, "test", "Value");
+                Cursor cursor = r.query(
+                        Settings.System.CONTENT_URI,
+                        new String[] {
+                            Settings.System.NAME,
+                            Settings.System.VALUE,
+                        }, null, null, null);
+
+                final ContentQueryMap cqm = new ContentQueryMap(
+                        cursor, Settings.System.NAME, true, null);
+                // Get the current state of the CQM. This forces a requery and means that the
+                // call to getValues() below won't do a requery().
+                cqm.getRows();
+                
+                // The cache won't notice changes until the loop runs.
+                Settings.System.putString(r, "test", "New Value");
+                ContentValues v = cqm.getValues("test");
+                String value = v.getAsString(Settings.System.VALUE);
+                assertEquals("Value", value);
+
+                // Use an Observer to find out when the cache does update.
+                cqm.addObserver(new Observer() {
+                    public void update(Observable o, Object arg) {
+                        // Should have the new values by now.
+                        ContentValues v = cqm.getValues("test");
+                        String value = v.getAsString(Settings.System.VALUE);
+                        assertEquals("New Value", value);
+                        Looper.myLooper().quit();
+                        cqm.close();
+                        mSuccess = true;
+                    }
+                });
+
+                // Give up after a few seconds, if it doesn't.
+                new Handler().postDelayed(new Runnable() {
+                    public void run() {
+                        fail("Timed out");
+                    }
+                }, 5000);
+            }
+        };
+
+        thread.start();
+        thread.join();
+        if (thread.mError != null) throw thread.mError;
+        assertTrue(thread.mSuccess);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CreateViewTest.java b/tests/AndroidTests/src/com/android/unit_tests/CreateViewTest.java
new file mode 100644
index 0000000..342094d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/CreateViewTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.View;
+import static android.view.ViewGroup.LayoutParams.FILL_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class CreateViewTest extends AndroidTestCase implements PerformanceTestCase {
+
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        return 0;
+    }
+
+    @SmallTest
+    public void testLayout1() throws Exception {
+        new CreateViewTest.ViewOne(mContext);
+    }
+
+    @SmallTest
+    public void testLayout2() throws Exception {
+        LinearLayout vert = new LinearLayout(mContext);
+        vert.addView(new CreateViewTest.ViewOne(mContext),
+                new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0));
+    }
+
+    @SmallTest
+    public void testLayout3() throws Exception {
+        LinearLayout vert = new LinearLayout(mContext);
+
+        ViewOne one = new ViewOne(mContext);
+        vert.addView(one, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0));
+
+        ViewOne two = new ViewOne(mContext);
+        vert.addView(two, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0));
+
+        ViewOne three = new ViewOne(mContext);
+        vert.addView(three, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0));
+
+        ViewOne four = new ViewOne(mContext);
+        vert.addView(four, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0));
+
+        ViewOne five = new ViewOne(mContext);
+        vert.addView(five, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0));
+
+        ViewOne six = new ViewOne(mContext);
+        vert.addView(six, new LinearLayout.LayoutParams(FILL_PARENT, FILL_PARENT, 0));
+    }
+
+    @SmallTest
+    public void testLayout4() throws Exception {
+        TextView text = new TextView(mContext);
+        text.setText("S");
+    }
+
+    @SmallTest
+    public void testLayout5() throws Exception {
+        TextView text = new TextView(mContext);
+        text.setText("S");
+
+        LinearLayout vert = new LinearLayout(mContext);
+        vert.addView(text, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0));
+    }
+
+    @SmallTest
+    public void testLayout6() throws Exception {
+        LinearLayout vert = new LinearLayout(mContext);
+
+        TextView one = new TextView(mContext);
+        one.setText("S");
+        vert.addView(one, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0));
+
+        TextView two = new TextView(mContext);
+        two.setText("M");
+        vert.addView(two, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0));
+
+        TextView three = new TextView(mContext);
+        three.setText("T");
+        vert.addView(three, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0));
+
+        TextView four = new TextView(mContext);
+        four.setText("W");
+        vert.addView(four, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0));
+
+        TextView five = new TextView(mContext);
+        five.setText("H");
+        vert.addView(five, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0));
+
+        TextView six = new TextView(mContext);
+        six.setText("F");
+        vert.addView(six, new LinearLayout.LayoutParams(FILL_PARENT, WRAP_CONTENT, 0));
+    }
+
+    public static class ViewOne extends View {
+        public ViewOne(Context context) {
+            super(context);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CursorWindowTest.java b/tests/AndroidTests/src/com/android/unit_tests/CursorWindowTest.java
new file mode 100644
index 0000000..d9068c8
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/CursorWindowTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.database.AbstractCursor;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.internal.database.ArrayListCursor;
+import android.database.CursorWindow;
+import android.test.PerformanceTestCase;
+
+import com.google.android.collect.Lists;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+public class CursorWindowTest extends TestCase implements PerformanceTestCase {
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+    // These test can only be run once.
+    public int startPerformance(Intermediates intermediates) {
+        return 1;
+    }
+
+    @SmallTest
+    public void testWriteCursorToWindow() throws Exception {
+        // create cursor
+        String[] colNames = new String[]{"name", "number", "profit"};
+        int colsize = colNames.length;
+        ArrayList<ArrayList> list = createTestList(10, colsize);
+        AbstractCursor cursor = new ArrayListCursor(colNames, (ArrayList<ArrayList>) list);
+
+        // fill window
+        CursorWindow window = new CursorWindow(false);
+        cursor.fillWindow(0, window);
+
+        // read from cursor window
+        for (int i = 0; i < list.size(); i++) {
+            ArrayList<Integer> col = list.get(i);
+            for (int j = 0; j < colsize; j++) {
+                String s = window.getString(i, j);
+                int r2 = col.get(j);
+                int r1 = Integer.parseInt(s);
+                assertEquals(r2, r1);
+            }
+        }
+
+        // test cursor window handle startpos != 0 
+        window.clear();
+        cursor.fillWindow(1, window);
+        // read from cursor from window
+        for (int i = 1; i < list.size(); i++) {
+            ArrayList<Integer> col = list.get(i);
+            for (int j = 0; j < colsize; j++) {
+                String s = window.getString(i, j);
+                int r2 = col.get(j);
+                int r1 = Integer.parseInt(s);
+                assertEquals(r2, r1);
+            }
+        }
+
+        // Clear the window and make sure it's empty
+        window.clear();
+        assertEquals(0, window.getNumRows());
+    }
+
+    @SmallTest
+    public void testValuesLocalWindow() {
+        doTestValues(new CursorWindow(true));
+    }
+    
+    @SmallTest
+    public void testValuesRemoteWindow() {
+        doTestValues(new CursorWindow(false));
+    }
+    
+    private void doTestValues(CursorWindow window) {
+        assertTrue(window.setNumColumns(7));
+        assertTrue(window.allocRow());
+        double db1 = 1.26;
+        assertTrue(window.putDouble(db1, 0, 0));
+        double db2 = window.getDouble(0, 0);
+        assertEquals(db1, db2);
+
+        long int1 = Long.MAX_VALUE;
+        assertTrue(window.putLong(int1, 0, 1));
+        long int2 = window.getLong(0, 1);
+        assertEquals(int1, int2);
+
+        assertTrue(window.putString("1198032740000", 0, 3));
+        assertEquals("1198032740000", window.getString(0, 3));
+        assertEquals(1198032740000L, window.getLong(0, 3));
+
+        assertTrue(window.putString(Long.toString(1198032740000L), 0, 3));
+        assertEquals(Long.toString(1198032740000L), window.getString(0, 3));
+        assertEquals(1198032740000L, window.getLong(0, 3));
+        
+        assertTrue(window.putString(Double.toString(42.0), 0, 4));
+        assertEquals(Double.toString(42.0), window.getString(0, 4));
+        assertEquals(42.0, window.getDouble(0, 4));
+        
+        // put blob
+        byte[] blob = new byte[1000];
+        byte value = 99;
+        Arrays.fill(blob, value);
+        assertTrue(window.putBlob(blob, 0, 6));
+        assertTrue(Arrays.equals(blob, window.getBlob(0, 6)));
+    }
+
+    @SmallTest
+    public void testNull() {
+        CursorWindow window = getOneByOneWindow();
+
+        // Put in a null value and read it back as various types
+        assertTrue(window.putNull(0, 0));
+        assertNull(window.getString(0, 0));
+        assertEquals(0, window.getLong(0, 0));
+        assertEquals(0.0, window.getDouble(0, 0));
+        assertNull(window.getBlob(0, 0));
+    }
+
+    @SmallTest
+    public void testEmptyString() {
+        CursorWindow window = getOneByOneWindow();
+
+        // put size 0 string and read it back as various types
+        assertTrue(window.putString("", 0, 0));
+        assertEquals("", window.getString(0, 0));
+        assertEquals(0, window.getLong(0, 0));
+        assertEquals(0.0, window.getDouble(0, 0));
+    }
+
+    private CursorWindow getOneByOneWindow() {
+        CursorWindow window = new CursorWindow(false);
+        assertTrue(window.setNumColumns(1));
+        assertTrue(window.allocRow());
+        return window;
+    }
+    
+    private static ArrayList<ArrayList> createTestList(int rows, int cols) {
+        ArrayList<ArrayList> list = Lists.newArrayList();
+        Random generator = new Random();
+
+        for (int i = 0; i < rows; i++) {
+            ArrayList<Integer> col = Lists.newArrayList();
+            list.add(col);
+            for (int j = 0; j < cols; j++) {
+                // generate random number
+                Integer r = generator.nextInt();
+                col.add(r);
+            }
+        }
+        return list;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java
new file mode 100644
index 0000000..5df499d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseCursorTest.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.CursorIndexOutOfBoundsException;
+import android.database.DataSetObserver;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteCursor;
+import android.database.sqlite.SQLiteCursorDriver;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQuery;
+import android.database.sqlite.SQLiteStatement;
+import android.os.Looper;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+public class DatabaseCursorTest extends TestCase implements PerformanceTestCase {
+
+    private static final String sString1 = "this is a test";
+    private static final String sString2 = "and yet another test";
+    private static final String sString3 = "this string is a little longer, but still a test";
+
+    private static final int CURRENT_DATABASE_VERSION = 42;
+    private SQLiteDatabase mDatabase;
+    private File mDatabaseFile;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db");
+        if (mDatabaseFile.exists()) {
+            mDatabaseFile.delete();
+        }
+        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+        assertNotNull(mDatabase);
+        mDatabase.setVersion(CURRENT_DATABASE_VERSION);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        mDatabaseFile.delete();
+        super.tearDown();
+    }
+
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+    // These test can only be run once.
+    public int startPerformance(Intermediates intermediates) {
+        return 1;
+    }
+
+    private void populateDefaultTable() {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');");
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');");
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');");
+    }
+
+    @MediumTest
+    public void testCursorUpdate() {
+        mDatabase.execSQL(
+            "CREATE TABLE test (_id INTEGER PRIMARY KEY, d INTEGER, s INTEGER);");
+        for(int i = 0; i < 20; i++) {
+            mDatabase.execSQL("INSERT INTO test (d, s) VALUES (" + i + 
+                "," + i%2 + ");");
+        }
+        
+        Cursor c = mDatabase.query("test", null, "s = 0", null, null, null, null);
+        int dCol = c.getColumnIndexOrThrow("d");
+        int sCol = c.getColumnIndexOrThrow("s");
+        
+        int count = 0;
+        while (c.moveToNext()) {
+            assertTrue(c.updateInt(dCol, 3));
+            count++;
+        }
+        assertEquals(10, count);
+        
+        assertTrue(c.commitUpdates());
+        
+        assertTrue(c.requery());
+        
+        count = 0;
+        while (c.moveToNext()) {
+            assertEquals(3, c.getInt(dCol));
+            count++;
+        }
+        
+        assertEquals(10, count);
+        assertTrue(c.moveToFirst());
+        assertTrue(c.deleteRow());
+        assertEquals(9, c.getCount());
+        c.close();
+    }
+    
+    @MediumTest
+    public void testBlob() throws Exception {
+        // create table
+        mDatabase.execSQL(
+            "CREATE TABLE test (_id INTEGER PRIMARY KEY, s TEXT, d REAL, l INTEGER, b BLOB);");
+        // insert blob
+        Object[] args = new Object[4];
+        
+        byte[] blob = new byte[1000];
+        byte value = 99;
+        Arrays.fill(blob, value);        
+        args[3] = blob;
+        
+        String s = new String("text");        
+        args[0] = s;
+        Double d = 99.9;
+        args[1] = d;
+        Long l = (long)1000;
+        args[2] = l;
+        
+        String sql = "INSERT INTO test (s, d, l, b) VALUES (?,?,?,?)";
+        mDatabase.execSQL(sql, args);
+        // use cursor to access blob
+        Cursor c = mDatabase.query("test", null, null, null, null, null, null);        
+        c.moveToNext();
+        ContentValues cv = new ContentValues();
+        DatabaseUtils.cursorRowToContentValues(c, cv);
+        
+        int bCol = c.getColumnIndexOrThrow("b");
+        int sCol = c.getColumnIndexOrThrow("s");
+        int dCol = c.getColumnIndexOrThrow("d");
+        int lCol = c.getColumnIndexOrThrow("l");
+        byte[] cBlob =  c.getBlob(bCol);
+        assertTrue(Arrays.equals(blob, cBlob));
+        assertEquals(s, c.getString(sCol));
+        assertEquals((double)d, c.getDouble(dCol));
+        assertEquals((long)l, c.getLong(lCol));
+        
+        // new byte[]
+        byte[] newblob = new byte[1000];
+        value = 98;
+        Arrays.fill(blob, value);        
+        
+        c.updateBlob(bCol, newblob);
+        cBlob =  c.getBlob(bCol);
+        assertTrue(Arrays.equals(newblob, cBlob));
+        
+        // commit
+        assertTrue(c.commitUpdates());
+        assertTrue(c.requery());
+        c.moveToNext();
+        cBlob =  c.getBlob(bCol);
+        assertTrue(Arrays.equals(newblob, cBlob));        
+        c.close();
+    }
+    
+    @MediumTest
+    public void testRealColumns() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data REAL);");
+        ContentValues values = new ContentValues();
+        values.put("data", 42.11);
+        long id = mDatabase.insert("test", "data", values);
+        assertTrue(id > 0);
+        Cursor c = mDatabase.rawQuery("SELECT data FROM test", null);
+        assertNotNull(c);
+        assertTrue(c.moveToFirst());
+        assertEquals(42.11, c.getDouble(0));
+        c.close();
+    }
+
+    @MediumTest
+    public void testCursor1() throws Exception {
+        populateDefaultTable();
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, null);
+
+        int dataColumn = c.getColumnIndexOrThrow("data");
+
+        // The cursor should ignore text before the last period when looking for a column. (This
+        // is a temporary hack in all implementations of getColumnIndex.)
+        int dataColumn2 = c.getColumnIndexOrThrow("junk.data");
+        assertEquals(dataColumn, dataColumn2);
+
+        assertSame(3, c.getCount());
+
+        assertTrue(c.isBeforeFirst());
+
+        try {
+            c.getInt(0);
+            fail("CursorIndexOutOfBoundsException expected");
+        } catch (CursorIndexOutOfBoundsException ex) {
+            // expected
+        }
+
+        c.moveToNext();
+        assertEquals(1, c.getInt(0));
+
+        String s = c.getString(dataColumn);
+        assertEquals(sString1, s);
+
+        c.moveToNext();
+        s = c.getString(dataColumn);
+        assertEquals(sString2, s);
+
+        c.moveToNext();
+        s = c.getString(dataColumn);
+        assertEquals(sString3, s);
+
+        c.moveToPosition(-1);
+        c.moveToNext();
+        s = c.getString(dataColumn);
+        assertEquals(sString1, s);
+
+        c.moveToPosition(2);
+        s = c.getString(dataColumn);
+        assertEquals(sString3, s);
+
+        int i;
+
+        for (c.moveToFirst(), i = 0; !c.isAfterLast(); c.moveToNext(), i++) {
+            c.getInt(0);
+        }
+
+        assertEquals(3, i);
+
+        try {
+            c.getInt(0);
+            fail("CursorIndexOutOfBoundsException expected");
+        } catch (CursorIndexOutOfBoundsException ex) {
+            // expected
+        }
+        c.close();
+    }
+
+    @MediumTest
+    public void testCursor2() throws Exception {
+        populateDefaultTable();
+
+        Cursor c = mDatabase.query("test", null, "_id > 1000", null, null, null, null);
+        assertEquals(0, c.getCount());
+        assertTrue(c.isBeforeFirst());
+
+        try {
+            c.getInt(0);
+            fail("CursorIndexOutOfBoundsException expected");
+        } catch (CursorIndexOutOfBoundsException ex) {
+            // expected
+        }
+
+        int i;
+        for (c.moveToFirst(), i = 0; !c.isAfterLast(); c.moveToNext(), i++) {
+            c.getInt(0);
+        }
+        assertEquals(0, i);
+        try {
+            c.getInt(0);
+            fail("CursorIndexOutOfBoundsException expected");
+        } catch (CursorIndexOutOfBoundsException ex) {
+            // expected
+        }
+        c.close();
+    }
+
+    @MediumTest
+    public void testLargeField() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        StringBuilder sql = new StringBuilder(2100);
+        sql.append("INSERT INTO test (data) VALUES ('");
+        Random random = new Random(System.currentTimeMillis());
+        StringBuilder randomString = new StringBuilder(1979);
+        for (int i = 0; i < 1979; i++) {
+            randomString.append((random.nextInt() & 0xf) % 10);
+        }
+        sql.append(randomString);
+        sql.append("');");
+        mDatabase.execSQL(sql.toString());
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+
+        assertTrue(c.moveToFirst());
+        assertEquals(0, c.getPosition());
+        String largeString = c.getString(c.getColumnIndexOrThrow("data"));
+        assertNotNull(largeString);
+        assertEquals(randomString.toString(), largeString);
+        c.close();
+    }
+
+    class TestObserver extends DataSetObserver {
+        int total;
+        SQLiteCursor c;
+        boolean quit = false;
+        public TestObserver(int total_, SQLiteCursor cursor) {
+            c = cursor;
+            total = total_;
+        }
+        
+        @Override
+        public void onChanged() {
+            int count = c.getCount();
+            if (total == count) {
+                int i = 0;
+                while (c.moveToNext()) {
+                    assertEquals(i, c.getInt(1));
+                    i++;
+                }
+                assertEquals(count, i);
+                quit = true;
+                Looper.myLooper().quit();
+            }
+        }
+
+        @Override
+        public void onInvalidated() {
+        }
+    }
+    
+    //@Large
+    @Suppress
+    public void testLoadingThreadDelayRegisterData() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
+        
+        final int count = 505; 
+        String sql = "INSERT INTO test (data) VALUES (?);";
+        SQLiteStatement s = mDatabase.compileStatement(sql);
+        for (int i = 0; i < count; i++) {
+            s.bindLong(1, i);
+            s.execute();
+        }
+
+        int maxRead = 500;
+        int initialRead = 5;
+        SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;",
+                null, initialRead, maxRead);
+        
+        TestObserver observer = new TestObserver(count, c);
+        c.getCount();
+        c.registerDataSetObserver(observer);
+        if (!observer.quit) {
+            Looper.loop();
+        }
+        c.close();
+    }
+    
+    @LargeTest
+    public void testLoadingThread() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
+        
+        final int count = 50000; 
+        String sql = "INSERT INTO test (data) VALUES (?);";
+        SQLiteStatement s = mDatabase.compileStatement(sql);
+        for (int i = 0; i < count; i++) {
+            s.bindLong(1, i);
+            s.execute();
+        }
+
+        int maxRead = 1000;
+        int initialRead = 5;
+        SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;",
+                null, initialRead, maxRead);
+        
+        TestObserver observer = new TestObserver(count, c);
+        c.registerDataSetObserver(observer);
+        c.getCount();
+        
+        Looper.loop();
+        c.close();
+    } 
+    
+    @LargeTest
+    public void testLoadingThreadClose() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
+        
+        final int count = 1000; 
+        String sql = "INSERT INTO test (data) VALUES (?);";
+        SQLiteStatement s = mDatabase.compileStatement(sql);
+        for (int i = 0; i < count; i++) {
+            s.bindLong(1, i);
+            s.execute();
+        }
+
+        int maxRead = 11;
+        int initialRead = 5;
+        SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;",
+                null, initialRead, maxRead);
+        
+        TestObserver observer = new TestObserver(count, c);
+        c.registerDataSetObserver(observer);
+        c.getCount();       
+        c.close();
+    }
+    
+    @LargeTest
+    public void testLoadingThreadDeactivate() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
+        
+        final int count = 1000; 
+        String sql = "INSERT INTO test (data) VALUES (?);";
+        SQLiteStatement s = mDatabase.compileStatement(sql);
+        for (int i = 0; i < count; i++) {
+            s.bindLong(1, i);
+            s.execute();
+        }
+
+        int maxRead = 11;
+        int initialRead = 5;
+        SQLiteCursor c = (SQLiteCursor)mDatabase.rawQuery("select * from test;",
+                null, initialRead, maxRead);
+        
+        TestObserver observer = new TestObserver(count, c);
+        c.registerDataSetObserver(observer);
+        c.getCount();       
+        c.deactivate();
+        c.close();
+    }
+    
+    @LargeTest
+    public void testManyRowsLong() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
+        
+        final int count = 36799; 
+        for (int i = 0; i < count; i++) {
+            mDatabase.execSQL("INSERT INTO test (data) VALUES (" + i + ");");
+        }
+
+        Cursor c = mDatabase.query("test", new String[]{"data"}, null, null, null, null, null);
+        assertNotNull(c);
+
+        int i = 0;
+        while (c.moveToNext()) {
+            assertEquals(i, c.getInt(0));
+            i++;
+        }
+        assertEquals(count, i);
+        assertEquals(count, c.getCount());
+
+        Log.d("testManyRows", "count " + Integer.toString(i));
+        c.close();
+    }
+
+    @LargeTest
+    public void testManyRowsTxt() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
+        StringBuilder sql = new StringBuilder(2100);
+        sql.append("INSERT INTO test (data) VALUES ('");
+        Random random = new Random(System.currentTimeMillis());
+        StringBuilder randomString = new StringBuilder(1979);
+        for (int i = 0; i < 1979; i++) {
+            randomString.append((random.nextInt() & 0xf) % 10);
+        }
+        sql.append(randomString);
+        sql.append("');");
+
+        // if cursor window size changed, adjust this value too  
+        final int count = 600; // more than two fillWindow needed
+        for (int i = 0; i < count; i++) {
+            mDatabase.execSQL(sql.toString());
+        }
+
+        Cursor c = mDatabase.query("test", new String[]{"data"}, null, null, null, null, null);
+        assertNotNull(c);
+
+        int i = 0;
+        while (c.moveToNext()) {
+            assertEquals(randomString.toString(), c.getString(0));
+            i++;
+        }
+        assertEquals(count, i);
+        assertEquals(count, c.getCount());
+        c.close();
+    }
+    
+    @LargeTest
+    public void testManyRowsTxtLong() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, txt TEXT, data INT);");
+        
+        Random random = new Random(System.currentTimeMillis());
+        StringBuilder randomString = new StringBuilder(1979);
+        for (int i = 0; i < 1979; i++) {
+            randomString.append((random.nextInt() & 0xf) % 10);
+        }
+
+        // if cursor window size changed, adjust this value too  
+        final int count = 600;
+        for (int i = 0; i < count; i++) {
+            StringBuilder sql = new StringBuilder(2100);
+            sql.append("INSERT INTO test (txt, data) VALUES ('");
+            sql.append(randomString);
+            sql.append("','");
+            sql.append(i);
+            sql.append("');");
+            mDatabase.execSQL(sql.toString());
+        }
+
+        Cursor c = mDatabase.query("test", new String[]{"txt", "data"}, null, null, null, null, null);
+        assertNotNull(c);
+
+        int i = 0;
+        while (c.moveToNext()) {
+            assertEquals(randomString.toString(), c.getString(0));
+            assertEquals(i, c.getInt(1));
+            i++;
+        }
+        assertEquals(count, i);
+        assertEquals(count, c.getCount());
+        c.close();
+    }
+   
+    @MediumTest
+    public void testRequery() throws Exception {
+        populateDefaultTable();
+
+        Cursor c = mDatabase.rawQuery("SELECT * FROM test", null);
+        assertNotNull(c);
+        assertEquals(3, c.getCount());
+        c.deactivate();
+        c.requery();
+        assertEquals(3, c.getCount());
+        c.close();
+    }
+
+    @MediumTest
+    public void testRequeryWithSelection() throws Exception {
+        populateDefaultTable();
+
+        Cursor c = mDatabase.rawQuery("SELECT data FROM test WHERE data = '" + sString1 + "'",
+                null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        assertTrue(c.moveToFirst());
+        assertEquals(sString1, c.getString(0));
+        c.deactivate();
+        c.requery();
+        assertEquals(1, c.getCount());
+        assertTrue(c.moveToFirst());
+        assertEquals(sString1, c.getString(0));
+        c.close();
+    }
+
+    @MediumTest
+    public void testRequeryWithSelectionArgs() throws Exception {
+        populateDefaultTable();
+
+        Cursor c = mDatabase.rawQuery("SELECT data FROM test WHERE data = ?",
+                new String[]{sString1});
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        assertTrue(c.moveToFirst());
+        assertEquals(sString1, c.getString(0));
+        c.deactivate();
+        c.requery();
+        assertEquals(1, c.getCount());
+        assertTrue(c.moveToFirst());
+        assertEquals(sString1, c.getString(0));
+        c.close();
+    }
+
+    @MediumTest
+    public void testRequeryWithAlteredSelectionArgs() throws Exception {
+        /**
+         * Test the ability of a subclass of SQLiteCursor to change its query arguments.
+         */
+        populateDefaultTable();
+
+        SQLiteDatabase.CursorFactory factory = new SQLiteDatabase.CursorFactory() {
+            public Cursor newCursor(
+                    SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable,
+                    SQLiteQuery query) {
+                return new SQLiteCursor(db, masterQuery, editTable, query) {
+                    @Override
+                    public boolean requery() {
+                        setSelectionArguments(new String[]{"2"});
+                        return super.requery();
+                    }
+                };
+            }
+        };
+        Cursor c = mDatabase.rawQueryWithFactory(
+                factory, "SELECT data FROM test WHERE _id <= ?", new String[]{"1"},
+                null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        assertTrue(c.moveToFirst());
+        assertEquals(sString1, c.getString(0));
+
+        // Our hacked requery() changes the query arguments in the cursor.
+        c.requery();
+
+        assertEquals(2, c.getCount());
+        assertTrue(c.moveToFirst());
+        assertEquals(sString1, c.getString(0));
+        assertTrue(c.moveToNext());
+        assertEquals(sString2, c.getString(0));
+
+        // Test that setting query args on a deactivated cursor also works.
+        c.deactivate();
+        c.requery();
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
new file mode 100644
index 0000000..b004c93
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
@@ -0,0 +1,871 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.ContentValues;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.CharArrayBuffer;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteStatement;
+import android.os.Handler;
+import android.os.Parcel;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.text.Collator;
+import java.util.Arrays;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX;
+import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX;
+
+public class DatabaseGeneralTest extends TestCase implements PerformanceTestCase {
+
+    private static final String sString1 = "this is a test";
+    private static final String sString2 = "and yet another test";
+    private static final String sString3 = "this string is a little longer, but still a test";
+    private static final String PHONE_NUMBER = "16175551212";
+
+    private static final int CURRENT_DATABASE_VERSION = 42;
+    private SQLiteDatabase mDatabase;
+    private File mDatabaseFile;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db");
+        if (mDatabaseFile.exists()) {
+            mDatabaseFile.delete();
+        }
+        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+        assertNotNull(mDatabase);
+        mDatabase.setVersion(CURRENT_DATABASE_VERSION);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        mDatabaseFile.delete();
+        super.tearDown();
+    }
+
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+    // These test can only be run once.
+    public int startPerformance(Intermediates intermediates) {
+        return 1;
+    }
+
+    private void populateDefaultTable() {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');");
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');");
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');");
+    }
+
+    @MediumTest
+    public void testVersion() throws Exception {
+        assertEquals(CURRENT_DATABASE_VERSION, mDatabase.getVersion());
+        mDatabase.setVersion(11);
+        assertEquals(11, mDatabase.getVersion());
+    }
+
+    @MediumTest
+    public void testUpdate() throws Exception {
+        populateDefaultTable();
+
+        ContentValues values = new ContentValues(1);
+        values.put("data", "this is an updated test");
+        assertEquals(1, mDatabase.update("test", values, "_id=1", null));
+        Cursor c = mDatabase.query("test", null, "_id=1", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        String value = c.getString(c.getColumnIndexOrThrow("data"));
+        assertEquals("this is an updated test", value);
+    }
+
+    @MediumTest
+    public void testPhoneNumbersEqual() throws Exception {
+        mDatabase.execSQL("CREATE TABLE phones (num TEXT);");
+        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('911');");
+        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('5555');");
+        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('+" + PHONE_NUMBER + "');");
+
+        String number;
+        Cursor c;
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '504-555-7683')", null, null, null, null);
+        assertTrue(c == null || c.getCount() == 0);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '911')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("911", number);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '5555')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("5555", number);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '180055555555')", null, null, null, null);
+        assertTrue(c == null || c.getCount() == 0);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '+" + PHONE_NUMBER + "')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("+" + PHONE_NUMBER, number);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '+1 (617).555-1212')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("+" + PHONE_NUMBER, number);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '+1 (617).555-1212p1234')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("+" + PHONE_NUMBER, number);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '" + PHONE_NUMBER + "')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("+" + PHONE_NUMBER, number);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '5551212')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("+" + PHONE_NUMBER, number);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '011" + PHONE_NUMBER + "')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("+" + PHONE_NUMBER, number);
+        c.close();
+
+        c = mDatabase.query("phones", null,
+                "PHONE_NUMBERS_EQUAL(num, '00" + PHONE_NUMBER + "')", null, null, null, null);
+        assertNotNull(c);
+        assertEquals(1, c.getCount());
+        c.moveToFirst();
+        number = c.getString(c.getColumnIndexOrThrow("num"));
+        assertEquals("+" + PHONE_NUMBER, number);
+        c.close();
+    }
+
+    /**
+     * Tests international matching issues for the PHONE_NUMBERS_EQUAL function.
+     * 
+     * @throws Exception
+     */
+    public void testPhoneNumbersEqualInternationl() throws Exception {
+        Cursor c;
+        String[] phoneNumbers = new String[2];
+
+        // Russian trunk digit
+        phoneNumbers[0] = "+79161234567"; // globablly dialable number
+        phoneNumbers[1] = "89161234567"; // in-country dialable number
+        c = mDatabase.rawQuery(
+                "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END",
+                phoneNumbers);
+        assertTrue(c.moveToFirst());
+        assertEquals("equal", c.getString(0));
+        c.close();
+
+        // French trunk digit
+        phoneNumbers[0] = "+33123456789"; // globablly dialable number
+        phoneNumbers[1] = "0123456789"; // in-country dialable number
+        c = mDatabase.rawQuery(
+                "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END",
+                phoneNumbers);
+        assertTrue(c.moveToFirst());
+        assertEquals("equal", c.getString(0));
+        c.close();
+
+
+        // Trunk digit for city codes in the Netherlands
+        phoneNumbers[0] = "+31771234567"; // globablly dialable number
+        phoneNumbers[1] = "0771234567"; // in-country dialable number
+        c = mDatabase.rawQuery(
+                "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END",
+                phoneNumbers);
+        assertTrue(c.moveToFirst());
+        assertEquals("equal", c.getString(0));
+        c.close();
+
+        // Test broken caller ID seen on call from Thailand to the US
+        phoneNumbers[0] = "+66811234567"; // in address book
+        phoneNumbers[1] = "166811234567"; // came in from the network
+        c = mDatabase.rawQuery(
+                "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END",
+                phoneNumbers);
+        assertTrue(c.moveToFirst());
+        assertEquals("equal", c.getString(0));
+        c.close();
+
+        // Test the same in-country number with different country codes
+        phoneNumbers[0] = "+33123456789";
+        phoneNumbers[1] = "+1123456789";
+        c = mDatabase.rawQuery(
+                "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END",
+                phoneNumbers);
+        assertTrue(c.moveToFirst());
+        assertEquals("not equal", c.getString(0));
+        c.close();
+
+        // Test one number with country code and the other without
+        phoneNumbers[0] = "5125551212";
+        phoneNumbers[1] = "+15125551212";
+        c = mDatabase.rawQuery(
+                "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END",
+                phoneNumbers);
+        assertTrue(c.moveToFirst());
+        assertEquals("equal", c.getString(0));
+        c.close();
+
+        // Test two NANP numbers that only differ in the area code
+        phoneNumbers[0] = "5125551212";
+        phoneNumbers[1] = "6505551212";
+        c = mDatabase.rawQuery(
+                "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END",
+                phoneNumbers);
+        assertTrue(c.moveToFirst());
+        assertEquals("not equal", c.getString(0));
+        c.close();
+    }
+
+    @MediumTest
+    public void testCopyString() throws Exception {
+        mDatabase.execSQL("CREATE TABLE guess (numi INTEGER, numf FLOAT, str TEXT);");
+        mDatabase.execSQL(
+                "INSERT INTO guess (numi,numf,str) VALUES (0,0.0,'ZoomZoomZoomZoom');");
+        mDatabase.execSQL("INSERT INTO guess (numi,numf,str) VALUES (2000000000,3.1415926535,'');");
+        String chinese = "\u4eac\u4ec5 \u5c3d\u5f84\u60ca";
+        String[] arr = new String[1];
+        arr[0] = chinese;
+        mDatabase.execSQL("INSERT INTO guess (numi,numf,str) VALUES (-32768,-1.0,?)", arr);
+
+        Cursor c;
+
+        c = mDatabase.rawQuery("SELECT * FROM guess", null);
+        
+        c.moveToFirst();
+        
+        CharArrayBuffer buf = new CharArrayBuffer(14);
+        
+        String compareTo = c.getString(c.getColumnIndexOrThrow("numi"));
+        int numiIdx = c.getColumnIndexOrThrow("numi");
+        int numfIdx = c.getColumnIndexOrThrow("numf");
+        int strIdx = c.getColumnIndexOrThrow("str");
+        
+        c.copyStringToBuffer(numiIdx, buf);
+        assertEquals(1, buf.sizeCopied);
+        assertEquals(compareTo, new String(buf.data, 0, buf.sizeCopied));
+        
+        c.copyStringToBuffer(strIdx, buf);
+        assertEquals("ZoomZoomZoomZoom", new String(buf.data, 0, buf.sizeCopied));
+        
+        c.moveToNext();
+        compareTo = c.getString(numfIdx);
+        
+        c.copyStringToBuffer(numfIdx, buf);
+        assertEquals(compareTo, new String(buf.data, 0, buf.sizeCopied));
+        c.copyStringToBuffer(strIdx, buf);
+        assertEquals(0, buf.sizeCopied);
+        
+        c.moveToNext();
+        c.copyStringToBuffer(numfIdx, buf);
+        assertEquals(-1.0, Double.valueOf(
+                new String(buf.data, 0, buf.sizeCopied)).doubleValue());
+        
+        c.copyStringToBuffer(strIdx, buf);
+        compareTo = c.getString(strIdx);
+        assertEquals(chinese, compareTo);
+       
+        assertEquals(chinese, new String(buf.data, 0, buf.sizeCopied));
+        c.close();
+    }
+    
+    @MediumTest
+    public void testSchemaChange1() throws Exception {
+        SQLiteDatabase db1 = mDatabase;
+        Cursor cursor;
+
+        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        cursor = db1.query("db1", null, null, null, null, null, null);
+        assertNotNull("Cursor is null", cursor);
+
+        db1.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        assertEquals(0, cursor.getCount());
+        cursor.deactivate();
+    }
+
+    @MediumTest
+    public void testSchemaChange2() throws Exception {
+        SQLiteDatabase db1 = mDatabase;
+        SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null);
+        Cursor cursor;
+
+        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        cursor = db1.query("db1", null, null, null, null, null, null);
+        assertNotNull("Cursor is null", cursor);
+        assertEquals(0, cursor.getCount());
+        cursor.deactivate();
+        // this cause exception because we're still using sqlite_prepate16 and not
+        // sqlite_prepare16_v2. The v2 variant added the ability to check the
+        // schema version and handle the case when the schema has changed
+        // Marco Nelissen claim it was 2x slower to compile SQL statements so
+        // I reverted back to the v1 variant.
+        /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        cursor = db1.query("db1", null, null, null, null, null, null);
+        assertNotNull("Cursor is null", cursor);
+        assertEquals(0, cursor.count());
+        cursor.deactivate();
+        */
+    }
+
+    @MediumTest
+    public void testSchemaChange3() throws Exception {
+        SQLiteDatabase db1 = mDatabase;
+        SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null);
+        Cursor cursor;
+
+
+        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
+        db1.execSQL("INSERT INTO db1 (data) VALUES ('test');");
+
+        cursor = db1.query("db1", null, null, null, null, null, null);
+        // this cause exception because we're still using sqlite_prepate16 and not
+        // sqlite_prepare16_v2. The v2 variant added the ability to check the
+        // schema version and handle the case when the schema has changed
+        // Marco Nelissen claim it was 2x slower to compile SQL statements so
+        // I reverted back to the v1 variant.
+        /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        assertNotNull("Cursor is null", cursor);
+        assertEquals(1, cursor.count());
+        assertTrue(cursor.first());
+        assertEquals("test", cursor.getString(cursor.getColumnIndexOrThrow("data")));
+        cursor.deactivate();
+        */
+    }
+
+    private class ChangeObserver extends ContentObserver {
+        private int mCursorNotificationCount = 0;
+        private int mNotificationCount = 0;
+
+        public int getCursorNotificationCount() {
+            return mCursorNotificationCount;
+        }
+
+        public int getNotificationCount() {
+            return mNotificationCount;
+        }
+
+        public ChangeObserver(boolean cursor) {
+            super(new Handler());
+            mCursor = cursor;
+        }
+
+        @Override
+        public boolean deliverSelfNotifications() {
+            return true;
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            if (mCursor) {
+                mCursorNotificationCount++;
+            } else {
+                mNotificationCount++;
+            }
+        }
+
+        boolean mCursor;
+    }
+
+    @MediumTest
+    public void testNotificationTest1() throws Exception {
+        /*
+        Cursor c = mContentResolver.query(Notes.CONTENT_URI,
+                new String[] {Notes._ID, Notes.NOTE},
+                null, null);
+        c.registerContentObserver(new MyContentObserver(true));
+        int count = c.count();
+
+        MyContentObserver observer = new MyContentObserver(false);
+        mContentResolver.registerContentObserver(Notes.CONTENT_URI, true, observer);
+
+        Uri uri;
+
+        HashMap<String, String> values = new HashMap<String, String>();
+        values.put(Notes.NOTE, "test note1");
+        uri = mContentResolver.insert(Notes.CONTENT_URI, values);
+        assertEquals(1, mCursorNotificationCount);
+        assertEquals(1, mNotificationCount);
+
+        c.requery();
+        assertEquals(count + 1, c.count());
+        c.first();
+        assertEquals("test note1", c.getString(c.getColumnIndex(Notes.NOTE)));
+        c.updateString(c.getColumnIndex(Notes.NOTE), "test note2");
+        c.commitUpdates();
+
+        assertEquals(2, mCursorNotificationCount);
+        assertEquals(2, mNotificationCount);
+
+        mContentResolver.delete(uri, null);
+
+        assertEquals(3, mCursorNotificationCount);
+        assertEquals(3, mNotificationCount);
+
+        mContentResolver.unregisterContentObserver(observer);
+        */
+    }
+
+    @MediumTest
+    public void testSelectionArgs() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
+        ContentValues values = new ContentValues(1);
+        values.put("data", "don't forget to handled 's");
+        mDatabase.insert("test", "data", values);
+        values.clear();
+        values.put("data", "no apostrophes here");
+        mDatabase.insert("test", "data", values);
+        Cursor c = mDatabase.query(
+                "test", null, "data GLOB ?", new String[]{"*'*"}, null, null, null);
+        assertEquals(1, c.getCount());
+        assertTrue(c.moveToFirst());
+        assertEquals("don't forget to handled 's", c.getString(1));
+        c.deactivate();
+
+        // make sure code should checking null string properly so that
+        // it won't crash
+        try {
+            mDatabase.query("test", new String[]{"_id"},
+                    "_id=?", new String[]{null}, null, null, null);
+            fail("expected exception not thrown");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+    
+    @MediumTest
+    public void testTokenize() throws Exception {
+        Cursor c;
+        mDatabase.execSQL("CREATE TABLE tokens (" +
+                "token TEXT COLLATE unicode," +
+                "source INTEGER " +
+                ");");
+        String[] cols =  new String[]{"token", "source"};
+        
+        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT _TOKENIZE(NULL, NULL, NULL, NULL)", null));
+        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
+                "SELECT _TOKENIZE('tokens', NULL, NULL, NULL)", null));
+        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT _TOKENIZE('tokens', 10, NULL, NULL)", null));
+        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT _TOKENIZE('tokens', 10, 'some string', NULL)", null));
+     
+        Assert.assertEquals(3, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT _TOKENIZE('tokens', 1, 'some string ok', ' ')", null)); 
+        
+        // test Chinese
+        String chinese = new String("\u4eac\u4ec5 \u5c3d\u5f84\u60ca"); 
+        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT _TOKENIZE('tokens', 1,'" + chinese + "', ' ')", null));
+        
+        String icustr = new String("Fr\u00e9d\u00e9ric Hj\u00f8nnev\u00e5g");
+        
+        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT _TOKENIZE('tokens', 1, '" + icustr + "', ' ')", null));   
+        
+        Assert.assertEquals(7, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens;", null));      
+
+        String key = DatabaseUtils.getHexCollationKey("Frederic Hjonneva");
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));      
+        key = DatabaseUtils.getHexCollationKey("Hjonneva");
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
+        
+        key = DatabaseUtils.getHexCollationKey("some string ok");
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
+        key = DatabaseUtils.getHexCollationKey("string");
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
+        key = DatabaseUtils.getHexCollationKey("ok");
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
+        
+        key = DatabaseUtils.getHexCollationKey(chinese);
+        String[] a = new String[1];
+        a[0] = key;
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token= ?", a));
+        a[0] += "*";
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+             "SELECT count(*) from tokens where token GLOB ?", a));        
+
+       Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token= '" + key + "'", null));
+        
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));        
+        
+        key = DatabaseUtils.getHexCollationKey("\u4eac\u4ec5");
+        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
+        
+        
+        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase, 
+                "SELECT count(*) from tokens where token GLOB 'ab*'", null));        
+    }
+    
+    @MediumTest
+    public void testTransactions() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num INTEGER);");
+        mDatabase.execSQL("INSERT INTO test (num) VALUES (0)");
+
+        // Make sure that things work outside an explicit transaction.
+        setNum(1);
+        checkNum(1);
+
+        // Test a single-level transaction.
+        setNum(0);
+        mDatabase.beginTransaction();
+        setNum(1);
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+        checkNum(1);
+        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
+
+        // Test a rolled-back transaction.
+        setNum(0);
+        mDatabase.beginTransaction();
+        setNum(1);
+        mDatabase.endTransaction();
+        checkNum(0);
+        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
+
+        // We should get an error if we end a non-existent transaction.
+        assertThrowsIllegalState(new Runnable() { public void run() {
+            mDatabase.endTransaction();
+        }});
+
+        // We should get an error if a set a non-existent transaction as clean.
+        assertThrowsIllegalState(new Runnable() { public void run() {
+            mDatabase.setTransactionSuccessful();
+        }});
+
+        mDatabase.beginTransaction();
+        mDatabase.setTransactionSuccessful();
+        // We should get an error if we mark a transaction as clean twice.
+        assertThrowsIllegalState(new Runnable() { public void run() {
+            mDatabase.setTransactionSuccessful();
+        }});
+        // We should get an error if we begin a transaction after marking the parent as clean.
+        assertThrowsIllegalState(new Runnable() { public void run() {
+            mDatabase.beginTransaction();
+        }});
+        mDatabase.endTransaction();
+        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
+
+        // Test a two-level transaction.
+        setNum(0);
+        mDatabase.beginTransaction();
+        mDatabase.beginTransaction();
+        setNum(1);
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+        checkNum(1);
+        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
+
+        // Test rolling back an inner transaction.
+        setNum(0);
+        mDatabase.beginTransaction();
+        mDatabase.beginTransaction();
+        setNum(1);
+        mDatabase.endTransaction();
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+        checkNum(0);
+        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
+
+        // Test rolling back an outer transaction.
+        setNum(0);
+        mDatabase.beginTransaction();
+        mDatabase.beginTransaction();
+        setNum(1);
+        mDatabase.setTransactionSuccessful();
+        mDatabase.endTransaction();
+        mDatabase.endTransaction();
+        checkNum(0);
+        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
+    }
+
+    private void setNum(int num) {
+        mDatabase.execSQL("UPDATE test SET num = " + num);
+    }
+
+    private void checkNum(int num) {
+        Assert.assertEquals(
+                num, DatabaseUtils.longForQuery(mDatabase, "SELECT num FROM test", null));
+    }
+
+    private void assertThrowsIllegalState(Runnable r) {
+        boolean ok = false;
+        try {
+            r.run();
+        } catch (IllegalStateException e) {
+            ok = true;
+        }
+        Assert.assertTrue(ok);
+    }
+
+    // Disable these until we can explicitly mark them as stress tests
+    public void xxtestMem1() throws Exception {
+        populateDefaultTable();
+
+        for (int i = 0; i < 50000; i++) {
+            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
+            cursor.moveToFirst();
+            cursor.close();
+//                Log.i("~~~~", "Finished round " + i);
+        }
+    }
+
+    // Disable these until we can explicitly mark them as stress tests
+    public void xxtestMem2() throws Exception {
+        populateDefaultTable();
+
+        for (int i = 0; i < 50000; i++) {
+            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
+            cursor.close();
+//                Log.i("~~~~", "Finished round " + i);
+        }
+    }
+
+    // Disable these until we can explicitly mark them as stress tests
+    public void xxtestMem3() throws Exception {
+        populateDefaultTable();
+
+        for (int i = 0; i < 50000; i++) {
+            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
+            cursor.deactivate();
+//                Log.i("~~~~", "Finished round " + i);
+        }
+    }
+
+    @MediumTest
+    public void testContentValues() throws Exception {
+        ContentValues values = new ContentValues();
+        values.put("string", "value");
+        assertEquals("value", values.getAsString("string"));
+        byte[] bytes = new byte[42];
+        Arrays.fill(bytes, (byte) 0x28);
+        values.put("byteArray", bytes);
+        assertTrue(Arrays.equals(bytes, values.getAsByteArray("byteArray")));
+
+        // Write the ContentValues to a Parcel and then read them out
+        Parcel p = Parcel.obtain();
+        values.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        values = ContentValues.CREATOR.createFromParcel(p);
+
+        // Read the values out again and make sure they're the same
+        assertTrue(Arrays.equals(bytes, values.getAsByteArray("byteArray")));
+        assertEquals("value", values.get("string"));
+    }
+
+    @MediumTest
+    public void testTableInfoPragma() throws Exception {
+        mDatabase.execSQL("CREATE TABLE pragma_test (" +
+                "i INTEGER DEFAULT 1234, " +
+                "j INTEGER, " +
+                "s TEXT DEFAULT 'hello', " +
+                "t TEXT, " +
+                "'select' TEXT DEFAULT \"hello\")");
+        try {
+            Cursor cur = mDatabase.rawQuery("PRAGMA table_info(pragma_test)", null);
+            Assert.assertEquals(5, cur.getCount());
+
+            Assert.assertTrue(cur.moveToNext());
+            Assert.assertEquals("i",
+                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
+            Assert.assertEquals("1234",
+                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
+
+            Assert.assertTrue(cur.moveToNext());
+            Assert.assertEquals("j",
+                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
+            Assert.assertNull(cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
+
+            Assert.assertTrue(cur.moveToNext());
+            Assert.assertEquals("s",
+                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
+            Assert.assertEquals("'hello'",
+                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
+
+            Assert.assertTrue(cur.moveToNext());
+            Assert.assertEquals("t",
+                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
+            Assert.assertNull(cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
+
+            Assert.assertTrue(cur.moveToNext());
+            Assert.assertEquals("select",
+                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
+            Assert.assertEquals("\"hello\"",
+                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
+
+            cur.close();
+        } catch (Throwable t) {
+            throw new RuntimeException(
+                    "If you see this test fail, it's likely that something about " +
+                    "sqlite's PRAGMA table_info(...) command has changed.", t);
+        }
+    }
+
+    @MediumTest
+    public void testInsertHelper() throws Exception {
+        Cursor cur;
+        ContentValues cv;
+        long row;
+
+        mDatabase.execSQL("CREATE TABLE insert_test (" +
+                "_id INTEGER PRIMARY KEY, " +
+                "s TEXT NOT NULL UNIQUE, " +
+                "t TEXT NOT NULL DEFAULT 'hello world', " +
+                "i INTEGER, " +
+                "j INTEGER NOT NULL DEFAULT 1234, " +
+                "'select' TEXT)");
+
+        DatabaseUtils.InsertHelper ih =
+            new DatabaseUtils.InsertHelper(mDatabase, "insert_test");
+
+        cv = new ContentValues();
+        cv.put("s", "one");
+        row = ih.insert(cv);
+        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
+        Assert.assertTrue(cur.moveToFirst());
+        Assert.assertEquals("one", cur.getString(1));
+        Assert.assertEquals("hello world", cur.getString(2));
+        Assert.assertNull(cur.getString(3));
+        Assert.assertEquals(1234, cur.getLong(4));
+        Assert.assertNull(cur.getString(5));
+
+        cv = new ContentValues();
+        cv.put("s", "two");
+        cv.put("t", "goodbye world");
+        row = ih.insert(cv);
+        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
+        Assert.assertTrue(cur.moveToFirst());
+        Assert.assertEquals("two", cur.getString(1));
+        Assert.assertEquals("goodbye world", cur.getString(2));
+        Assert.assertNull(cur.getString(3));
+        Assert.assertEquals(1234, cur.getLong(4));
+        Assert.assertNull(cur.getString(5));
+
+        cv = new ContentValues();
+        cv.put("t", "goodbye world");
+        row = ih.insert(cv);
+        Assert.assertEquals(-1, row);
+
+        cv = new ContentValues();
+        cv.put("s", "three");
+        cv.put("i", 2345);
+        cv.put("j", 3456);
+        cv.put("select", "tricky");
+        row = ih.insert(cv);
+        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
+        Assert.assertTrue(cur.moveToFirst());
+        Assert.assertEquals("three", cur.getString(1));
+        Assert.assertEquals("hello world", cur.getString(2));
+        Assert.assertEquals(2345, cur.getLong(3));
+        Assert.assertEquals(3456, cur.getLong(4));
+        Assert.assertEquals("tricky", cur.getString(5));
+
+        cv = new ContentValues();
+        cv.put("s", "three");
+        cv.put("i", 6789);
+        row = ih.insert(cv);
+        Assert.assertEquals(-1, row);
+        row = ih.replace(cv);
+        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
+        Assert.assertTrue(cur.moveToFirst());
+        Assert.assertEquals("three", cur.getString(1));
+        Assert.assertEquals("hello world", cur.getString(2));
+        Assert.assertEquals(6789, cur.getLong(3));
+
+        ih.close();
+    }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java
new file mode 100644
index 0000000..0560c21
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLocaleTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.database.sqlite.SQLiteDatabase;
+import android.database.Cursor;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.test.MoreAsserts;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+import junit.framework.TestCase;
+
+public class DatabaseLocaleTest extends TestCase {
+
+    private SQLiteDatabase mDatabase;
+
+    private static final String[] STRINGS = {
+        "c\u00f4t\u00e9",
+        "cote",
+        "c\u00f4te",
+        "cot\u00e9",
+        "boy",
+        "dog",
+        "COTE",
+    };
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDatabase = SQLiteDatabase.create(null);
+        mDatabase.execSQL("CREATE TABLE test (data TEXT COLLATE LOCALIZED);");
+        for (String s : STRINGS) {
+            mDatabase.execSQL("INSERT INTO test VALUES('" + s + "');");
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        super.tearDown();
+    }
+
+    private String[] query(String sql) {
+        Log.i("LocaleTest", "Querying: " + sql);
+        Cursor c = mDatabase.rawQuery(sql, null);
+        assertNotNull(c);
+        ArrayList<String> items = new ArrayList<String>();
+        while (c.moveToNext()) {
+            items.add(c.getString(0));
+            Log.i("LocaleTest", "...." + c.getString(0));
+        }
+        String[] result = items.toArray(new String[items.size()]);
+        assertEquals(STRINGS.length, result.length);
+        c.close();
+        return result;
+    }
+
+    @MediumTest
+    public void testLocaleInsertOrder() throws Exception {
+        String[] results = query("SELECT data FROM test");
+        MoreAsserts.assertEquals(STRINGS, results);
+    }
+
+    @MediumTest
+    public void testLocaleenUS() throws Exception {
+        Log.i("LocaleTest", "about to call setLocale en_US");
+        mDatabase.setLocale(new Locale("en", "US"));
+        String[] results;
+        results = query("SELECT data FROM test ORDER BY data COLLATE LOCALIZED ASC");
+
+        // The database code currently uses PRIMARY collation strength,
+        // meaning that all versions of a character compare equal (regardless
+        // of case or accents), leaving the "cote" flavors in database order.
+        MoreAsserts.assertEquals(results, new String[] {
+                STRINGS[4],  // "boy"
+                STRINGS[0],  // sundry forms of "cote"
+                STRINGS[1],
+                STRINGS[2],
+                STRINGS[3],
+                STRINGS[6],  // "COTE"
+                STRINGS[5],  // "dog"
+        });
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseLockTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLockTest.java
new file mode 100644
index 0000000..bb821e3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseLockTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2009 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.unit_tests;
+
+import android.app.Activity;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import java.io.File;
+import java.util.concurrent.atomic.AtomicInteger;
+import android.test.AndroidTestCase;
+
+import junit.framework.TestCase;
+
+/* 
+ * This is a series of unit tests for database locks.
+ */
+public class DatabaseLockTest extends AndroidTestCase {
+
+    private static final int NUM_ITERATIONS = 100;
+    private static final int SLEEP_TIME = 30;
+    private static final int MAX_ALLOWED_LATENCY_TIME = 30;
+    private SQLiteDatabase mDatabase;
+    private File mDatabaseFile;
+    private AtomicInteger mCounter = new AtomicInteger();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        File parentDir = getContext().getFilesDir();
+        mDatabaseFile = new File(parentDir, "database_test.db");
+        
+        if (mDatabaseFile.exists()) {
+            mDatabaseFile.delete();
+        }
+        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+        assertNotNull(mDatabase);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        mDatabaseFile.delete();
+        super.tearDown();
+    }
+
+    /*
+     * testLockFairness() tests the fairness of prioritizing multiple threads 
+     * attempting to access a database concurrently.
+     * This test is intended to verify that, when two threads are accessing the
+     * same database at the same time with the same prioritization, neither thread 
+     * is locked out and prevented from accessing the database.
+     */
+    @LargeTest
+    public void testLockFairness() {
+        startDatabaseFairnessThread();
+        int previous = 0;
+        for (int i = 0; i < NUM_ITERATIONS; i++) { 
+            mDatabase.beginTransaction();
+            int val = mCounter.get();
+            if (i == 0) {
+                previous = val - i;
+            }
+            assertTrue(previous == (val - i));
+            try {
+                Thread.currentThread().sleep(SLEEP_TIME); 
+            } catch (InterruptedException e) {
+                // ignore
+            }
+            mDatabase.endTransaction();
+        }
+    }
+    
+    /*
+     * This function is to create the second thread for testLockFairness() test.
+     */
+    private void startDatabaseFairnessThread() {
+        Thread thread = new DatabaseFairnessThread();
+        thread.start();
+    }
+
+    private class DatabaseFairnessThread extends Thread {
+        @Override
+        public void run() {
+            for (int i = 0; i < NUM_ITERATIONS; i++) {
+                mDatabase.beginTransaction();
+                int val = mCounter.incrementAndGet();
+                try {
+                    Thread.currentThread().sleep(SLEEP_TIME);
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+                mDatabase.endTransaction();
+            }
+        }
+    }    
+    
+    /*
+     * testLockLatency() tests the latency of database locks.
+     * This test is intended to verify that, even when two threads are accessing
+     * the same database, the locking/unlocking of the database is done within an
+     * appropriate amount of time (MAX_ALLOWED_LATENCY_TIME).
+     */
+    @LargeTest
+    public void testLockLatency() {
+        startDatabaseLatencyThread();
+        int previous = 0;
+        long sumTime = 0;
+        long maxTime = 0;
+        for (int i = 0; i < NUM_ITERATIONS; i++) { 
+            long startTime = System.currentTimeMillis();
+            mDatabase.beginTransaction();
+            long endTime = System.currentTimeMillis();
+            long elapsedTime = endTime - startTime;
+            if (maxTime < elapsedTime) {
+                maxTime = elapsedTime;
+            }
+            sumTime += elapsedTime;
+            try {
+                Thread.currentThread().sleep(SLEEP_TIME); 
+            } catch (InterruptedException e) {
+                // ignore
+            }   
+            mDatabase.endTransaction();
+        }
+        long averageTime = sumTime/NUM_ITERATIONS;
+        Log.i("DatabaseLockLatency", "AverageTime: " + averageTime);
+        Log.i("DatabaseLockLatency", "MaxTime: " + maxTime);
+        assertTrue( (averageTime - SLEEP_TIME) <= MAX_ALLOWED_LATENCY_TIME);
+    }
+    
+    /*
+     * This function is to create the second thread for testLockLatency() test.
+     */
+    private void startDatabaseLatencyThread() {
+        Thread thread = new DatabaseLatencyThread();
+        thread.start();
+    }
+
+    private class DatabaseLatencyThread extends Thread {
+        @Override
+        public void run() {
+            for (int i = 0; i < NUM_ITERATIONS; i++) 
+            {
+                mDatabase.beginTransaction();
+                try {
+                    Thread.currentThread().sleep(SLEEP_TIME);
+                } catch (InterruptedException e) {
+                    // ignore
+                } 
+                mDatabase.endTransaction();
+            }
+        }
+    }        
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabasePerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/DatabasePerformanceTests.java
new file mode 100644
index 0000000..68ce5e1
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabasePerformanceTests.java
@@ -0,0 +1,1353 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import junit.framework.Assert;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.provider.Contacts;
+import android.provider.Contacts.People;
+import android.test.PerformanceTestCase;
+import android.test.TestCase;
+
+import java.io.File;
+import java.util.Random;
+
+/**
+ * Database Performance Tests
+ * 
+ */
+
+public class DatabasePerformanceTests {
+
+    public static String[] children() {
+        return new String[] {
+            ContactReadingTest1.class.getName(),
+            Perf1Test.class.getName(),
+            Perf2Test.class.getName(),
+            Perf3Test.class.getName(),
+            Perf4Test.class.getName(),
+            Perf5Test.class.getName(),
+            Perf6Test.class.getName(),
+            Perf7Test.class.getName(),
+            Perf8Test.class.getName(),
+            Perf9Test.class.getName(),
+            Perf10Test.class.getName(),
+            Perf11Test.class.getName(),
+            Perf12Test.class.getName(),
+            Perf13Test.class.getName(),
+            Perf14Test.class.getName(),
+            Perf15Test.class.getName(),
+            Perf16Test.class.getName(),
+            Perf17Test.class.getName(),
+            Perf18Test.class.getName(),
+            Perf19Test.class.getName(),
+            Perf20Test.class.getName(),
+            Perf21Test.class.getName(),
+            Perf22Test.class.getName(),
+            Perf23Test.class.getName(),
+            Perf24Test.class.getName(),
+            Perf25Test.class.getName(),
+            Perf26Test.class.getName(),
+            Perf27Test.class.getName(),
+            Perf28Test.class.getName(),
+            Perf29Test.class.getName(),
+            Perf30Test.class.getName(),
+            Perf31Test.class.getName(),
+            };
+    }
+       
+    public static abstract class PerformanceBase implements TestCase,
+            PerformanceTestCase {
+        protected static final int CURRENT_DATABASE_VERSION = 42;
+        protected SQLiteDatabase mDatabase;
+        protected File mDatabaseFile;
+        protected Context mContext;
+
+        public void setUp(Context c) {
+            mContext = c;
+            mDatabaseFile = new File("/tmp", "perf_database_test.db");
+            if (mDatabaseFile.exists()) {
+                mDatabaseFile.delete();
+            }
+            mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+            Assert.assertTrue(mDatabase != null);
+            mDatabase.setVersion(CURRENT_DATABASE_VERSION);
+        }
+
+        public void tearDown() {
+            mDatabase.close();
+            mDatabaseFile.delete();
+        }
+
+        public boolean isPerformanceOnly() {
+            return true;
+        }
+
+        // These test can only be run once.
+        public int startPerformance(Intermediates intermediates) {
+            return 0;
+        }
+
+        public void run() {
+        }
+
+        public String numberName(int number) {
+            String result = "";
+
+            if (number >= 1000) {
+                result += numberName((number / 1000)) + " thousand";
+                number = (number % 1000);
+
+                if (number > 0) result += " ";
+            }
+
+            if (number >= 100) {
+                result += ONES[(number / 100)] + " hundred";
+                number = (number % 100);
+
+                if (number > 0) result += " ";
+            }
+
+            if (number >= 20) {
+                result += TENS[(number / 10)];
+                number = (number % 10);
+
+                if (number > 0) result += " ";
+            }
+
+            if (number > 0) {
+                result += ONES[number];
+            }
+
+            return result;
+        }
+    }
+
+    /**
+     * Test reading all contact data.
+     */
+    public static class ContactReadingTest1 implements TestCase, PerformanceTestCase {
+        private static final String[] PEOPLE_PROJECTION = new String[] {
+               Contacts.People._ID, // 0
+               Contacts.People.PRIMARY_PHONE_ID, // 1
+               Contacts.People.TYPE, // 2
+               Contacts.People.NUMBER, // 3
+               Contacts.People.LABEL, // 4
+               Contacts.People.NAME, // 5
+               Contacts.People.PRESENCE_STATUS, // 6
+        };
+
+        private Cursor mCursor;
+
+        public void setUp(Context c) {
+            mCursor = c.getContentResolver().query(People.CONTENT_URI, PEOPLE_PROJECTION, null,
+                    null, People.DEFAULT_SORT_ORDER);
+        }
+        
+        public void tearDown() {
+            mCursor.close();
+        }
+
+        public boolean isPerformanceOnly() {
+            return true;
+        }
+
+        public int startPerformance(Intermediates intermediates) {
+            // This test can only be run once.
+            return 0;
+        }
+
+        public void run() {
+            while (mCursor.moveToNext()) {
+                // Read out all of the data
+                mCursor.getLong(0);
+                mCursor.getLong(1);
+                mCursor.getLong(2);
+                mCursor.getString(3);
+                mCursor.getString(4);
+                mCursor.getString(5);
+                mCursor.getLong(6);
+            }
+        }
+    }
+    
+    /**
+     * Test 1000 inserts
+     */
+    
+    public static class Perf1Test extends PerformanceBase {
+        private static final int SIZE = 1000;
+
+        private String[] statements = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                statements[i] =
+                        "INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                                + numberName(r) + "')";
+            }
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.execSQL(statements[i]);
+            }
+        }
+    }
+
+    /**
+     * Test 1000 inserts into and indexed table
+     */
+    
+    public static class Perf2Test extends PerformanceBase {
+        private static final int SIZE = 1000;
+
+        private String[] statements = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                statements[i] =
+                        "INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                                + numberName(r) + "')";
+            }
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.execSQL(statements[i]);
+            }
+        }
+    }
+
+    /**
+     * 100 SELECTs without an index
+     */
+      
+    public static class Perf3Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] = "b >= " + lower + " AND b < " + upper;
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase
+                        .query("t1", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     * 100 SELECTs on a string comparison
+     */
+    
+    public static class Perf4Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                where[i] = "c LIKE '" + numberName(i) + "'";
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase
+                        .query("t1", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     * 100 SELECTs with an index
+     */
+    
+    public static class Perf5Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] = "b >= " + lower + " AND b < " + upper;
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase
+                        .query("t1", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     *  INNER JOIN without an index
+     */
+    
+    public static class Perf6Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"t1.a"};
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase
+              .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+        }
+
+        @Override
+        public void run() {
+            mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null,
+                    null, null, null, null);
+        }
+    }
+
+    /**
+     *  INNER JOIN without an index on one side
+     */
+    
+    public static class Perf7Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"t1.a"};
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase
+              .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+        }
+
+        @Override
+        public void run() {
+            mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null,
+                    null, null, null, null);
+        }
+    }
+
+    /**
+     *  INNER JOIN without an index on one side
+     */
+    
+    public static class Perf8Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"t1.a"};
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase
+              .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+        }
+
+        @Override
+        public void run() {
+            mDatabase.query("t1 INNER JOIN t2 ON t1.c = t2.c", COLUMNS, null,
+                    null, null, null, null);
+        }
+    }
+
+    /**
+     *  100 SELECTs with subqueries. Subquery is using an index
+     */
+    
+    public static class Perf9Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"t1.a"};
+
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase
+              .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            mDatabase.execSQL("CREATE INDEX i2b ON t2(b)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] =
+                        "t1.b IN (SELECT t2.b FROM t2 WHERE t2.b >= " + lower
+                                + " AND t2.b < " + upper + ")";
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase
+                        .query("t1", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     *  100 SELECTs on string comparison with Index
+     */
+
+    public static class Perf10Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i3c ON t1(c)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                where[i] = "c LIKE '" + numberName(i) + "'";
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase
+                        .query("t1", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     *  100 SELECTs on integer 
+     */
+    
+    public static class Perf11Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"b"};
+
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     *  100 SELECTs on String
+     */
+
+    public static class Perf12Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"c"};
+
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     *  100 SELECTs on integer with index
+     */
+    
+    public static class Perf13Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"b"};
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i1b on t1(b)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     *  100 SELECTs on String with index
+     */
+
+    public static class Perf14Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"c"};      
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     *  100 SELECTs on String with starts with
+     */
+
+    public static class Perf15Test extends PerformanceBase {
+        private static final int SIZE = 100;
+        private static final String[] COLUMNS = {"c"};
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                where[i] = "c LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+            }
+
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase
+                        .query("t1", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+
+    /**
+     *  1000  Deletes on an indexed table
+     */
+    
+    public static class Perf16Test extends PerformanceBase {
+        private static final int SIZE = 1000;
+        private static final String[] COLUMNS = {"c"};
+        
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i3c ON t1(c)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.delete("t1", null, null);
+            }
+        }
+    }
+
+    /**
+     *  1000  Deletes
+     */
+    
+    public static class Perf17Test extends PerformanceBase {
+        private static final int SIZE = 1000;
+        private static final String[] COLUMNS = {"c"};       
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.delete("t1", null, null);
+            }
+        }
+    }
+
+    /**
+     *  1000 DELETE's without an index with where clause 
+     */
+    
+    public static class Perf18Test extends PerformanceBase {
+        private static final int SIZE = 1000;
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] = "b >= " + lower + " AND b < " + upper;
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.delete("t1", where[i], null);
+            }
+        }
+    }
+
+    /**
+     *  1000 DELETE's with an index with where clause 
+     */
+    
+    public static class Perf19Test extends PerformanceBase {
+        private static final int SIZE = 1000;
+        private String[] where = new String[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] = "b >= " + lower + " AND b < " + upper;
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.delete("t1", where[i], null);
+            }
+        }
+    }
+
+    /**
+     *  1000 update's with an index with where clause 
+     */
+    
+    public static class Perf20Test extends PerformanceBase {
+        private static final int SIZE = 1000;
+        private String[] where = new String[SIZE];
+        ContentValues[] mValues = new ContentValues[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] = "b >= " + lower + " AND b < " + upper;
+                ContentValues b = new ContentValues(1);
+                b.put("b", upper);
+                mValues[i] = b;
+               
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.update("t1", mValues[i], where[i], null);
+            }
+        }
+    }
+
+    /**
+     *  1000 update's without an index with where clause 
+     */
+    
+    public static class Perf21Test extends PerformanceBase {
+        private static final int SIZE = 1000;       
+        private String[] where = new String[SIZE];
+        ContentValues[] mValues = new ContentValues[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+           
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] = "b >= " + lower + " AND b < " + upper;
+                ContentValues b = new ContentValues(1);
+                b.put("b", upper);
+                mValues[i] = b;
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.update("t1", mValues[i], where[i], null);
+            }
+        }
+    }
+    
+    /**
+     *  10000 inserts for an integer 
+     */
+    
+    public static class Perf22Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        ContentValues[] mValues = new ContentValues[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER)");
+           
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                ContentValues b = new ContentValues(1);
+                b.put("a", r);
+                mValues[i] = b;
+            }
+        }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.insert("t1", null, mValues[i]);
+            }
+        }
+    }
+    
+    /**
+     *  10000 inserts for an integer -indexed table
+     */
+    
+    public static class Perf23Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        ContentValues[] mValues = new ContentValues[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a INTEGER)");
+            mDatabase.execSQL("CREATE INDEX i1a ON t1(a)");
+           
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                ContentValues b = new ContentValues(1);
+                b.put("a", r);
+                mValues[i] = b;
+            }
+        }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.insert("t1", null, mValues[i]);
+            }
+        }
+    }
+    
+    /**
+     *  10000 inserts for a String 
+     */
+    
+    public static class Perf24Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        ContentValues[] mValues = new ContentValues[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a VARCHAR(100))");
+           
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                ContentValues b = new ContentValues(1);
+                b.put("a", numberName(r));
+                mValues[i] = b;
+            }
+        }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.insert("t1", null, mValues[i]);
+            }
+        }
+    }
+    
+    /**
+     *  10000 inserts for a String - indexed table 
+     */
+    
+    public static class Perf25Test extends PerformanceBase {
+        private static final int SIZE = 10000;       
+        ContentValues[] mValues = new ContentValues[SIZE];
+
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t1(a VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i1a ON t1(a)");
+                       
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                ContentValues b = new ContentValues(1);
+                b.put("a", numberName(r));
+                mValues[i] = b; 
+            }
+        }
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.insert("t1", null, mValues[i]);
+            }
+        }
+    }
+    
+    
+    /**
+     *  10000 selects for a String -starts with
+     */
+    
+    public static class Perf26Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        private static final String[] COLUMNS = {"t3.a"};
+        private String[] where = new String[SIZE];
+        
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+                                  
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t3 VALUES('"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+            }
+        }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+    
+    /**
+     *  10000 selects for a String - indexed table -starts with
+     */
+    
+    public static class Perf27Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        private static final String[] COLUMNS = {"t3.a"};
+        private String[] where = new String[SIZE];
+        
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i3a ON t3(a)");
+                       
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t3 VALUES('"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+            }                              
+           }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+    
+    /**
+     *  10000 selects for an integer -
+     */
+    
+    public static class Perf28Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        private static final String[] COLUMNS = {"t4.a"};
+        private String[] where = new String[SIZE];
+        
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t4(a INTEGER)");
+           
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")");
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] = "a >= " + lower + " AND a < " + upper;
+            }
+           }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t4", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+    
+    /**
+     *  10000 selects for an integer -indexed table
+     */
+    
+    public static class Perf29Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        private static final String[] COLUMNS = {"t4.a"};
+        private String[] where = new String[SIZE];
+       
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t4(a INTEGER)");
+           mDatabase.execSQL("CREATE INDEX i4a ON t4(a)");
+           
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")");
+                
+                int lower = i * 100;
+                int upper = (i + 10) * 100;
+                where[i] = "a >= " + lower + " AND a < " + upper;
+            }
+           
+           }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t4", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+    
+    
+    /**
+     *  10000 selects for a String - contains 'e'
+     */
+    
+    public static class Perf30Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        private static final String[] COLUMNS = {"t3.a"};
+        private String[] where = new String[SIZE];
+        
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+            
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t3 VALUES('"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                 where[i] = "a LIKE '*e*'";
+
+            }                              
+           }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+    
+    /**
+     *  10000 selects for a String - contains 'e'-indexed table
+     */
+    
+    public static class Perf31Test extends PerformanceBase {
+        private static final int SIZE = 10000;
+        private static final String[] COLUMNS = {"t3.a"};
+        private String[] where = new String[SIZE];
+        
+        @Override
+        public void setUp(Context c) {
+            super.setUp(c);
+            Random random = new Random(42);
+
+            mDatabase
+              .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+            mDatabase.execSQL("CREATE INDEX i3a ON t3(a)");
+            
+            for (int i = 0; i < SIZE; i++) {
+                int r = random.nextInt(100000);
+                mDatabase.execSQL("INSERT INTO t3 VALUES('"
+                        + numberName(r) + "')");
+            }
+
+            for (int i = 0; i < SIZE; i++) {
+                where[i] = "a LIKE '*e*'";
+
+            }                              
+            
+           }        
+
+        @Override
+        public void run() {
+            for (int i = 0; i < SIZE; i++) {
+                mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+            }
+        }
+    }
+    
+    public static final String[] ONES =
+            {"zero", "one", "two", "three", "four", "five", "six", "seven",
+                "eight", "nine", "ten", "eleven", "twelve", "thirteen",
+                "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
+                "nineteen"};
+
+    public static final String[] TENS =
+            {"", "ten", "twenty", "thirty", "forty", "fifty", "sixty",
+                "seventy", "eighty", "ninety"};
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java
new file mode 100644
index 0000000..16ca59f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStatementTest.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteConstraintException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDoneException;
+import android.database.sqlite.SQLiteStatement;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.io.File;
+
+public class DatabaseStatementTest extends TestCase implements PerformanceTestCase {
+
+    private static final String sString1 = "this is a test";
+    private static final String sString2 = "and yet another test";
+    private static final String sString3 = "this string is a little longer, but still a test";
+    
+    private static final int CURRENT_DATABASE_VERSION = 42;
+    private SQLiteDatabase mDatabase;
+    private File mDatabaseFile;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDatabaseFile = new File("/sqlite_stmt_journals", "database_test.db");
+        if (mDatabaseFile.exists()) {
+            mDatabaseFile.delete();
+        }
+        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
+        assertNotNull(mDatabase);
+        mDatabase.setVersion(CURRENT_DATABASE_VERSION);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        mDatabaseFile.delete();
+        super.tearDown();
+    }
+
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+    // These test can only be run once.
+    public int startPerformance(Intermediates intermediates) {
+        return 1;
+    }
+
+    private void populateDefaultTable() {
+        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
+
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');");
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');");
+        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');");
+    }
+
+    @MediumTest
+    public void testExecuteStatement() throws Exception {
+        populateDefaultTable();
+        SQLiteStatement statement = mDatabase.compileStatement("DELETE FROM test");
+        statement.execute();
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, null);
+        assertEquals(0, c.getCount());
+        c.deactivate();
+        statement.close();
+    }
+
+    @MediumTest
+    public void testSimpleQuery() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL, str TEXT NOT NULL);");
+        mDatabase.execSQL("INSERT INTO test VALUES (1234, 'hello');");
+        SQLiteStatement statement1 =
+                mDatabase.compileStatement("SELECT num FROM test WHERE str = ?");
+        SQLiteStatement statement2 =
+                mDatabase.compileStatement("SELECT str FROM test WHERE num = ?");
+
+        try {
+            statement1.bindString(1, "hello");
+            long value = statement1.simpleQueryForLong();
+            assertEquals(1234, value);
+
+            statement1.bindString(1, "world");
+            statement1.simpleQueryForLong();
+            fail("shouldn't get here");
+        } catch (SQLiteDoneException e) {
+            // expected
+        }
+
+        try {
+            statement2.bindLong(1, 1234);
+            String value = statement1.simpleQueryForString();
+            assertEquals("hello", value);
+
+            statement2.bindLong(1, 5678);
+            statement1.simpleQueryForString();
+            fail("shouldn't get here");
+        } catch (SQLiteDoneException e) {
+            // expected
+        }
+
+        statement1.close();
+        statement2.close();
+    }
+
+    @MediumTest
+    public void testStatementLongBinding() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num INTEGER);");
+        SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)");
+
+        for (int i = 0; i < 10; i++) {
+            statement.bindLong(1, i);
+            statement.execute();
+        }
+        statement.close();
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, null);
+        int numCol = c.getColumnIndexOrThrow("num");
+        c.moveToFirst();
+        for (long i = 0; i < 10; i++) {
+            long num = c.getLong(numCol);
+            assertEquals(i, num);
+            c.moveToNext();
+        }
+        c.close();
+    }
+
+    @MediumTest
+    public void testStatementStringBinding() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num TEXT);");
+        SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)");
+
+        for (long i = 0; i < 10; i++) {
+            statement.bindString(1, Long.toHexString(i));
+            statement.execute();
+        }
+        statement.close();
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, null);
+        int numCol = c.getColumnIndexOrThrow("num");
+        c.moveToFirst();
+        for (long i = 0; i < 10; i++) {
+            String num = c.getString(numCol);
+            assertEquals(Long.toHexString(i), num);
+            c.moveToNext();
+        }
+        c.close();
+    }
+
+    @MediumTest
+    public void testStatementClearBindings() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num INTEGER);");
+        SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)");
+
+        for (long i = 0; i < 10; i++) {
+            statement.bindLong(1, i);
+            statement.clearBindings();
+            statement.execute();
+        }
+        statement.close();
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID");
+        int numCol = c.getColumnIndexOrThrow("num");
+        assertTrue(c.moveToFirst());
+        for (long i = 0; i < 10; i++) {
+            assertTrue(c.isNull(numCol));
+            c.moveToNext();
+        }
+        c.close();
+    }
+
+    @MediumTest
+    public void testSimpleStringBinding() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num TEXT, value TEXT);");
+        String statement = "INSERT INTO test (num, value) VALUES (?,?)";
+
+        String[] args = new String[2];
+        for (int i = 0; i < 2; i++) {
+            args[i] = Integer.toHexString(i);
+        }
+
+        mDatabase.execSQL(statement, args);
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, null);
+        int numCol = c.getColumnIndexOrThrow("num");
+        int valCol = c.getColumnIndexOrThrow("value");
+        c.moveToFirst();
+        String num = c.getString(numCol);
+        assertEquals(Integer.toHexString(0), num);
+
+        String val = c.getString(valCol);
+        assertEquals(Integer.toHexString(1), val);
+        c.close();
+    }
+
+    @MediumTest
+    public void testStatementMultipleBindings() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num INTEGER, str TEXT);");
+        SQLiteStatement statement =
+                mDatabase.compileStatement("INSERT INTO test (num, str) VALUES (?, ?)");
+
+        for (long i = 0; i < 10; i++) {
+            statement.bindLong(1, i);
+            statement.bindString(2, Long.toHexString(i));
+            statement.execute();
+        }
+        statement.close();
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID");
+        int numCol = c.getColumnIndexOrThrow("num");
+        int strCol = c.getColumnIndexOrThrow("str");
+        assertTrue(c.moveToFirst());
+        for (long i = 0; i < 10; i++) {
+            long num = c.getLong(numCol);
+            String str = c.getString(strCol);
+            assertEquals(i, num);
+            assertEquals(Long.toHexString(i), str);
+            c.moveToNext();
+        }
+        c.close();
+    }
+
+    private static class StatementTestThread extends Thread {
+        private SQLiteDatabase mDatabase;
+        private SQLiteStatement mStatement;
+
+        public StatementTestThread(SQLiteDatabase db, SQLiteStatement statement) {
+            super();
+            mDatabase = db;
+            mStatement = statement;
+        }
+
+        @Override
+        public void run() {
+            mDatabase.beginTransaction();
+            for (long i = 0; i < 10; i++) {
+                mStatement.bindLong(1, i);
+                mStatement.bindString(2, Long.toHexString(i));
+                mStatement.execute();
+            }
+            mDatabase.setTransactionSuccessful();
+            mDatabase.endTransaction();
+
+            Cursor c = mDatabase.query("test", null, null, null, null, null, "ROWID");
+            int numCol = c.getColumnIndexOrThrow("num");
+            int strCol = c.getColumnIndexOrThrow("str");
+            assertTrue(c.moveToFirst());
+            for (long i = 0; i < 10; i++) {
+                long num = c.getLong(numCol);
+                String str = c.getString(strCol);
+                assertEquals(i, num);
+                assertEquals(Long.toHexString(i), str);
+                c.moveToNext();
+            }
+            c.close();
+        }
+    }
+
+    @MediumTest
+    public void testStatementMultiThreaded() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num INTEGER, str TEXT);");
+        SQLiteStatement statement =
+                mDatabase.compileStatement("INSERT INTO test (num, str) VALUES (?, ?)");
+
+        StatementTestThread thread = new StatementTestThread(mDatabase, statement);
+        thread.start();
+        try {
+            thread.join();
+        } finally {
+            statement.close();
+        }
+    }
+
+    @MediumTest
+    public void testStatementConstraint() throws Exception {
+        mDatabase.execSQL("CREATE TABLE test (num INTEGER NOT NULL);");
+        SQLiteStatement statement = mDatabase.compileStatement("INSERT INTO test (num) VALUES (?)");
+
+        // Try to insert NULL, which violates the constraint
+        try {
+            statement.clearBindings();
+            statement.execute();
+            fail("expected exception not thrown");
+        } catch (SQLiteConstraintException e) {
+            // expected
+        }
+
+        // Make sure the statement can still be used
+        statement.bindLong(1, 1);
+        statement.execute();
+        statement.close();
+
+        Cursor c = mDatabase.query("test", null, null, null, null, null, null);
+        int numCol = c.getColumnIndexOrThrow("num");
+        c.moveToFirst();
+        long num = c.getLong(numCol);
+        assertEquals(1, num);
+        c.close();
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseStressTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStressTest.java
new file mode 100644
index 0000000..b110125
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseStressTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.content.Context;
+import android.database.sqlite.*;
+import android.util.Log;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+
+import java.io.File;
+
+// This test suite is too desctructive and takes too long to be included in the
+// automated suite.
+@Suppress
+public class DatabaseStressTest extends AndroidTestCase {
+    private static final String TAG = "DatabaseStressTest";    
+    private static final int CURRENT_DATABASE_VERSION = 1;
+    private SQLiteDatabase mDatabase;
+    private File mDatabaseFile;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Context c = getContext();
+        
+        mDatabaseFile = c.getDatabasePath("database_test.db");
+        if (mDatabaseFile.exists()) {
+            mDatabaseFile.delete();
+        }
+                
+        mDatabase = c.openOrCreateDatabase("database_test.db", 0, null);            
+       
+        assertNotNull(mDatabase);
+        mDatabase.setVersion(CURRENT_DATABASE_VERSION);
+        
+        mDatabase.execSQL("CREATE TABLE IF NOT EXISTS test (_id INTEGER PRIMARY KEY, data TEXT);");
+
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mDatabase.close();
+        mDatabaseFile.delete();
+        super.tearDown();
+    }
+
+    public void testSingleThreadInsertDelete() {        
+        int i = 0;
+        char[] ch = new char[100000];
+        String str = new String(ch);
+        String[] strArr = new String[1];
+        strArr[0] = str;
+        for (; i < 10000; ++i) {
+            try {
+                mDatabase.execSQL("INSERT INTO test (data) VALUES (?)", strArr);
+                mDatabase.execSQL("delete from test;");
+            } catch (Exception e) {
+                Log.e(TAG, "exception " + e.getMessage());                
+            }
+        }        
+    }
+   
+    /**
+     * use fillup -p 90 before run the test
+     * and when disk run out
+     * start delete some fillup files
+     * and see if db recover
+     */
+    public void testOutOfSpace() {
+        int i = 0;
+        char[] ch = new char[100000];
+        String str = new String(ch);
+        String[] strArr = new String[1];
+        strArr[0] = str;
+        for (; i < 10000; ++i) {
+            try {
+                mDatabase.execSQL("INSERT INTO test (data) VALUES (?)", strArr);
+            } catch (Exception e) {
+                Log.e(TAG, "exception " + e.getMessage());                
+            }
+        }        
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java
new file mode 100644
index 0000000..a7a1400
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseTests.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import junit.framework.TestSuite;
+
+public class DatabaseTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(DatabaseTests.class.getName());
+
+        suite.addTestSuite(DatabaseGeneralTest.class);
+        suite.addTestSuite(DatabaseCursorTest.class);
+        suite.addTestSuite(DatabaseStatementTest.class);
+        suite.addTestSuite(DatabaseLocaleTest.class);
+        suite.addTestSuite(CursorWindowTest.class);
+        suite.addTestSuite(DatabaseLockTest.class);
+
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DbSSLSessionCacheTest.java b/tests/AndroidTests/src/com/android/unit_tests/DbSSLSessionCacheTest.java
new file mode 100644
index 0000000..8d7d797
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/DbSSLSessionCacheTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.content.ContentResolver;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import com.google.android.net.GoogleHttpClient;
+
+import com.android.internal.net.DbSSLSessionCache;
+import com.android.internal.net.DbSSLSessionCache.DatabaseHelper;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.Certificate;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.security.cert.X509Certificate;
+
+/** Unit test for SSL session caching with {@link GoogleHttpClient}.
+ *  Uses network resources. 
+ */
+@Suppress
+public class DbSSLSessionCacheTest extends AndroidTestCase {
+    
+    protected void setUp() throws Exception {
+    }
+
+    protected void tearDown() throws Exception {
+    }
+
+    /** 
+     * We want to test the actual database write - the actual hooking into 
+     * low-level SSL is tested. 
+     */
+    @LargeTest
+    public void testSslCacheAdd() throws Exception {
+        // Let's verify the database has the rows.
+        // Use internal details of the implementation - could make the field
+        // visible for testing, but it's same.
+        
+        // Use default database
+        DbSSLSessionCache cache = DbSSLSessionCache.getInstanceForPackage(getContext());
+        cache.clear();
+        
+        
+        makeRequestInNewContext("https://www.google.com");
+
+        // Verify the key was inserted
+        SQLiteOpenHelper helper = new DatabaseHelper(getContext());
+        Cursor query = null;
+        try {
+            query = helper.getReadableDatabase().query(DbSSLSessionCache.SSL_CACHE_TABLE, 
+                    new String[] {"hostport"}, null, 
+                    null, null, null, null);
+
+            assertTrue(query.moveToFirst()); // one row inserted
+            String hostPort = query.getString(0);
+            assertEquals(hostPort, "www.google.com:443");
+        } finally {
+            query.close();
+        }
+    }
+    
+    @LargeTest
+    public void testExpire() throws Exception {
+        DatabaseHelper helper = new DatabaseHelper(getContext());
+        // clean up
+        DbSSLSessionCache cache = new DbSSLSessionCache(helper);
+        cache.clear();
+        
+        long t0 = System.currentTimeMillis();
+        for (int i = 0; i < DbSSLSessionCache.MAX_CACHE_SIZE + 2; i++) {
+            final int port = i;
+            cache.putSessionData(new MockSession() {
+                
+                public String getPeerHost() {
+                    return "test.host.com";
+                }
+                
+                public int getPeerPort() {
+                    return port;
+                }
+            }, new byte[256]);
+        }
+        long t1 = System.currentTimeMillis();
+
+        System.err.println("Time to insert " + 
+                (DbSSLSessionCache.MAX_CACHE_SIZE + 2) + " " + (t1 - t0));
+        
+        // first entry should have port 1.
+        Cursor query = helper.getReadableDatabase().query(DbSSLSessionCache.SSL_CACHE_TABLE, 
+                new String[] {"hostport", "session"}, null, 
+                null, null, null, null);
+
+        int cnt = query.getCount();
+        
+        assertTrue(query.moveToFirst()); // one row inserted
+        String hostPort = query.getString(0);
+        assertEquals("test.host.com:2", hostPort);
+        while (query.moveToNext()) {
+            hostPort = query.getString(0);
+            String session = query.getString(1);
+        }
+        long t2 = System.currentTimeMillis();
+        System.err.println("Time to load " + cnt + " " + (t2 - t1));
+        
+        query.close();
+    }
+    
+    private void makeRequestInNewContext(String url) throws IOException {
+        GoogleHttpClient client = new GoogleHttpClient(getContext(), "Test",
+                false /* no gzip */);
+
+        try {
+            // Note: we must test against a real server, because the connection
+            // gets established before the interceptor can crash the request.
+            HttpGet method = new HttpGet(url);
+            HttpResponse response = client.execute(method);
+        } finally {
+            client.close();
+        }
+    }
+    
+    private static class MockSession implements SSLSession {
+        
+        public String getPeerHost() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public int getPeerPort() {
+            throw new UnsupportedOperationException();
+        }
+
+
+        
+        public int getApplicationBufferSize() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public String getCipherSuite() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public long getCreationTime() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public byte[] getId() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public long getLastAccessedTime() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public Certificate[] getLocalCertificates() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public Principal getLocalPrincipal() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public int getPacketBufferSize() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public X509Certificate[] getPeerCertificateChain()
+                throws SSLPeerUnverifiedException {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public String getProtocol() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public SSLSessionContext getSessionContext() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public Object getValue(String name) {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public String[] getValueNames() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public void invalidate() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public boolean isValid() {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public void putValue(String name, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        
+        public void removeValue(String name) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ExpatPerformanceTest.java b/tests/AndroidTests/src/com/android/unit_tests/ExpatPerformanceTest.java
new file mode 100644
index 0000000..0d51047
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ExpatPerformanceTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.util.Xml;
+import org.kxml2.io.KXmlParser;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ExpatPerformanceTest extends AndroidTestCase {
+
+    private static final String TAG = ExpatPerformanceTest.class.getSimpleName();
+
+    private byte[] mXmlBytes;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        InputStream in = mContext.getResources().openRawResource(R.raw.youtube);
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int length;
+        while ((length = in.read(buffer)) != -1) {
+            out.write(buffer, 0, length);
+        }
+        mXmlBytes = out.toByteArray();
+
+        Log.i("***", "File size: " + (mXmlBytes.length / 1024) + "k");
+    }
+
+    @LargeTest
+    public void testPerformance() throws Exception {
+//        try {
+//            Debug.startMethodTracing("expat3");
+//        for (int i = 0; i < 1; i++) {
+            runJavaPullParser();
+            runSax();
+            runExpatPullParser();
+//        }
+//    } finally {
+//            Debug.stopMethodTracing();
+//        }
+    }
+
+    private InputStream newInputStream() {
+        return new ByteArrayInputStream(mXmlBytes);
+    }
+
+    private void runSax() throws IOException, SAXException {
+        long start = System.currentTimeMillis();
+        Xml.parse(newInputStream(), Xml.Encoding.UTF_8, new DefaultHandler());
+        long elapsed = System.currentTimeMillis() - start;
+        Log.i(TAG, "expat SAX: " + elapsed + "ms");
+    }
+
+    private void runExpatPullParser() throws XmlPullParserException, IOException {
+        long start = System.currentTimeMillis();
+        XmlPullParser pullParser = Xml.newPullParser();
+        pullParser.setInput(newInputStream(), "UTF-8");
+        withPullParser(pullParser);
+        long elapsed = System.currentTimeMillis() - start;
+        Log.i(TAG, "expat pull: " + elapsed + "ms");
+    }
+
+    private void runJavaPullParser() throws XmlPullParserException, IOException {
+        XmlPullParser pullParser;
+        long start = System.currentTimeMillis();
+        pullParser = new KXmlParser();
+        pullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+        pullParser.setInput(newInputStream(), "UTF-8");
+        withPullParser(pullParser);
+        long elapsed = System.currentTimeMillis() - start;
+        Log.i(TAG, "java pull parser: " + elapsed + "ms");
+    }
+
+    private static void withPullParser(XmlPullParser pullParser)
+            throws IOException, XmlPullParserException {
+        int eventType = pullParser.next();
+        while (eventType != XmlPullParser.END_DOCUMENT) {
+            switch (eventType) {
+                case XmlPullParser.START_TAG:
+                    pullParser.getName();
+//                        int nattrs = pullParser.getAttributeCount();
+//                        for (int i = 0; i < nattrs; ++i) {
+//                            pullParser.getAttributeName(i);
+//                            pullParser.getAttributeValue(i);
+//                        }
+                    break;
+                case XmlPullParser.END_TAG:
+                    pullParser.getName();
+                    break;
+                case XmlPullParser.TEXT:
+                    pullParser.getText();
+                    break;
+            }
+            eventType = pullParser.next();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/GDataParseTest.java b/tests/AndroidTests/src/com/android/unit_tests/GDataParseTest.java
new file mode 100644
index 0000000..af85483
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/GDataParseTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.res.XmlResourceParser;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Xml;
+import com.google.wireless.gdata.data.Entry;
+import com.google.wireless.gdata.data.Feed;
+import com.google.wireless.gdata.parser.ParseException;
+import com.google.wireless.gdata.parser.xml.XmlGDataParser;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Tests timing on parsing various formats of GData.
+ */
+public class GDataParseTest extends AndroidTestCase implements PerformanceTestCase {
+
+    private static void parseXml(InputStream is) throws ParseException, IOException {
+        XmlPullParser xmlParser = Xml.newPullParser();
+        XmlGDataParser parser = new XmlGDataParser(is, xmlParser);
+        Feed feed = parser.init();
+        Entry entry = null;
+        while (parser.hasMoreData()) {
+            entry = parser.readNextEntry(entry);
+        }
+    }
+
+    private static void parseXml(XmlPullParser xmlP) throws ParseException, IOException {
+        XmlGDataParser parser = new XmlGDataParser(null /* in */, xmlP);
+        Feed feed = parser.init();
+        Entry entry = null;
+        while (parser.hasMoreData()) {
+            entry = parser.readNextEntry(entry);
+        }
+    }
+
+    private static void dumpXml(XmlPullParser parser) throws
+            XmlPullParserException, IOException {
+        int eventType = parser.nextTag();
+        while (eventType != XmlPullParser.END_DOCUMENT) {
+            switch (eventType) {
+                case XmlPullParser.START_TAG:
+                    parser.getName();
+                    // System.out.print("<" + parser.getName());
+                    int nattrs = parser.getAttributeCount();
+                    for (int i = 0; i < nattrs; ++i) {
+                        parser.getAttributeName(i);
+                        parser.getAttributeValue(i);
+                        // System.out.print(" " + parser.getAttributeName(i) + "=\""
+                        //        + parser.getAttributeValue(i) + "\"");
+                    }
+                    // System.out.print(">");
+                    break;
+                case XmlPullParser.END_TAG:
+                    parser.getName();
+                    // System.out.print("</" + parser.getName() + ">");
+                    break;
+                case XmlPullParser.TEXT:
+                    parser.getText();
+                    // System.out.print(parser.getText());
+                    break;
+                default:
+                    // do nothing
+            }
+            eventType = parser.next();
+        }
+    }
+
+    private byte[] getBytesForResource(int resid) throws Exception {
+        // all resources are written into a zip file, so the InputStream we
+        // get for a resource is on top of zipped
+        // data.  in order to compare performance of parsing unzipped vs.
+        // zipped content, we first read the data into an in-memory buffer.
+        InputStream zipIs = null;
+        try {
+            zipIs = mContext.getResources().openRawResource(resid);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            byte buf[] = new byte[1024];
+            int bytesRead = zipIs.read(buf);
+            while (bytesRead > 0) {
+                baos.write(buf, 0, bytesRead);
+                bytesRead = zipIs.read(buf);
+            }
+            return baos.toByteArray();
+        } finally {
+            if (zipIs != null) {
+                zipIs.close();
+            }
+        }
+    }
+
+    public boolean isPerformanceOnly() {
+        return true;
+    }
+
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        return 0;
+    }
+
+    @MediumTest
+    public void testXml() throws Exception {
+        InputStream is = new ByteArrayInputStream(getBytesForResource(R.raw.calendarxml));
+        try {
+            is.reset();
+            parseXml(is);
+        } finally {
+            is.close();
+        }
+    }
+
+    @MediumTest
+    public void testXmlGzip() throws Exception {
+        InputStream gzIs = new GZIPInputStream(
+                new ByteArrayInputStream(getBytesForResource(R.raw.calendarxmlgz)));
+        try {
+            parseXml(gzIs);
+        } finally {
+            gzIs.close();
+        }
+    }
+
+    @MediumTest
+    public void testJson() throws Exception {
+        String jsonString = new String(getBytesForResource(R.raw.calendarjs), "UTF-8");
+        JSONTokener tokens = new JSONTokener(jsonString);
+        assertNotNull(new JSONObject(tokens));
+    }
+
+    @SmallTest
+    public void testBinaryXml() throws Exception {
+        XmlResourceParser parser = mContext.getResources().getXml(R.xml.calendar);
+        parseXml(parser);
+        parser.close();
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/GeocoderTest.java b/tests/AndroidTests/src/com/android/unit_tests/GeocoderTest.java
new file mode 100644
index 0000000..e28a7dc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/GeocoderTest.java
@@ -0,0 +1,64 @@
+package com.android.unit_tests;
+
+/*
+ * Copyright (C) 2007 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.
+ */
+
+import android.location.Address;
+import android.location.Geocoder;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+import java.util.List;
+
+@Suppress
+public class GeocoderTest extends AndroidTestCase {
+
+    public void testGeocoder() throws Exception {
+        Locale locale = new Locale("en", "us");
+        Geocoder g = new Geocoder(mContext, locale);
+
+        List<Address> addresses1 = g.getFromLocation(37.435067, -122.166767, 2);
+        assertNotNull(addresses1);
+        assertEquals(1, addresses1.size());
+
+        Address addr = addresses1.get(0);
+        assertEquals("94305", addr.getFeatureName());
+        assertEquals("Palo Alto, CA 94305", addr.getAddressLine(0));
+        assertEquals("USA", addr.getAddressLine(1));
+        assertEquals("94305", addr.getPostalCode());
+        assertFalse(Math.abs(addr.getLatitude() - 37.4240385) > 0.1);
+
+        List<Address> addresses2 = g.getFromLocationName("San Francisco, CA", 1);
+        assertNotNull(addresses2);
+        assertEquals(1, addresses2.size());
+
+        addr = addresses2.get(0);
+        assertEquals("San Francisco", addr.getFeatureName());
+        assertEquals("San Francisco, CA", addr.getAddressLine(0));
+        assertEquals("United States", addr.getAddressLine(1));
+        assertEquals("San Francisco", addr.getLocality());
+        assertEquals("CA", addr.getAdminArea());
+        assertEquals(null, addr.getPostalCode());
+
+        assertFalse(Math.abs(addr.getLatitude() - 37.77916) > 0.1);
+
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/GoogleHttpClientTest.java b/tests/AndroidTests/src/com/android/unit_tests/GoogleHttpClientTest.java
new file mode 100644
index 0000000..d970de3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/GoogleHttpClientTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.content.ContentResolver;
+import android.net.http.AndroidHttpClient;
+import android.provider.Checkin;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import com.google.android.collect.Lists;
+import com.google.android.net.GoogleHttpClient;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+
+/** Unit test for {@link GoogleHttpClient}. */
+public class GoogleHttpClientTest extends AndroidTestCase {
+    private TestHttpServer mServer;
+    private String mServerUrl;
+
+    protected void setUp() throws Exception {
+        // Run a test server that echoes the URI back to the caller.
+        mServer = new TestHttpServer();
+        mServer.registerHandler("*", new HttpRequestHandler() {
+            public void handle(
+                    HttpRequest request,
+                    HttpResponse response,
+                    HttpContext context) throws HttpException, IOException {
+                 String uri = request.getRequestLine().getUri();
+                 response.setEntity(new StringEntity(uri));
+            }
+        });
+
+        mServer.start();
+        mServerUrl = "http://localhost:" + mServer.getPort() + "/";
+    }
+
+    protected void tearDown() throws Exception {
+        if (mServer != null) mServer.shutdown();
+    }
+
+    @LargeTest
+    public void testThreadCheck() throws Exception {
+        ContentResolver resolver = getContext().getContentResolver();
+        GoogleHttpClient client = new GoogleHttpClient(resolver, "Test",
+                false /* no gzip */);
+
+        try {
+            // Note: we must test against a real server, because the connection
+            // gets established before the interceptor can crash the request.
+            HttpGet method = new HttpGet(mServerUrl);
+
+            // This is actually an AndroidHttpClient feature...
+            // TODO: somehow test that Activity threads have the flag set?
+            AndroidHttpClient.setThreadBlocked(true);
+
+            try {
+                client.execute(method);
+                fail("\"thread forbids HTTP requests\" exception expected");
+            } catch (RuntimeException e) {
+                if (!e.toString().contains("forbids HTTP requests")) throw e;
+            } finally {
+                AndroidHttpClient.setThreadBlocked(false);
+            }
+
+            HttpResponse response = client.execute(method);
+            assertEquals("/", EntityUtils.toString(response.getEntity()));
+        } finally {
+            client.close();
+        }
+    }
+
+    @MediumTest
+    public void testUrlRewriteRules() throws Exception {
+        // Don't do anything exotic; UrlRulesTest checks the actual rewriter.
+        // Just make sure that URLs are, in fact, rewritten.
+
+        // TODO: Use a MockContentProvider/MockContentResolver instead.
+        ContentResolver resolver = getContext().getContentResolver();
+        GoogleHttpClient client = new GoogleHttpClient(resolver, "Test",
+                false /* not gzip capable */);
+        Settings.Gservices.putString(resolver,
+                "url:test", "http://foo.bar/ rewrite " + mServerUrl + "new/");
+
+        // Update the digest, so the UrlRules cache is reloaded.
+        Settings.Gservices.putString(resolver, "digest", mServerUrl);
+
+        try {
+            HttpGet method = new HttpGet("http://foo.bar/path");
+            HttpResponse response = client.execute(method);
+            String body = EntityUtils.toString(response.getEntity());
+            assertEquals("/new/path", body);
+        } finally {
+            client.close();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/GoogleLoginServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/GoogleLoginServiceTest.java
new file mode 100644
index 0000000..59f14bf
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/GoogleLoginServiceTest.java
@@ -0,0 +1,145 @@
+// Copyright 2008 The Android Open Source Project
+// All rights reserved.
+
+package com.android.unit_tests;
+
+import java.util.Arrays;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.Condition;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+import com.google.android.googleapps.GoogleLoginCredentialsResult;
+import com.google.android.googleapps.IGoogleLoginService;
+import com.google.android.googlelogin.GoogleLoginServiceConstants;
+
+import junit.framework.Assert;
+
+// Suppress until bug http://b/issue?id=1416570 is fixed
+@Suppress
+/** Unit test for the Google login service. */
+public class GoogleLoginServiceTest extends AndroidTestCase {
+    private static final String TAG = "GoogleLoginServiceTest";
+
+    private IGoogleLoginService mGls = null;
+    private Lock mGlsLock = new ReentrantLock();
+    private Condition mGlsCv = mGlsLock.newCondition();
+
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className, IBinder service) {
+            mGlsLock.lock();
+            try {
+                mGls = IGoogleLoginService.Stub.asInterface(service);
+                mGlsCv.signalAll();
+            } finally {
+                mGlsLock.unlock();
+            }
+            Log.v(TAG, "service is connected");
+        }
+        public void onServiceDisconnected(ComponentName className) {
+            mGlsLock.lock();
+            try {
+                mGls = null;
+                mGlsCv.signalAll();
+            } finally {
+                mGlsLock.unlock();
+            }
+            Log.v(TAG, "service is disconnected");
+        }
+    };
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        getContext().bindService((new Intent())
+                                 .setClassName("com.google.android.googleapps",
+                                               "com.google.android.googleapps.GoogleLoginService"),
+                                 mConnection, Context.BIND_AUTO_CREATE);
+
+        // wait for the service to cnnnect
+        mGlsLock.lock();
+        try {
+            while (mGls == null) {
+                try {
+                    mGlsCv.await();
+                } catch (InterruptedException ignore) {
+                }
+            }
+        } finally {
+            mGlsLock.unlock();
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getContext().unbindService(mConnection);
+        super.tearDown();
+    }
+
+    public void testSingleAccountScheme() throws Exception {
+        Assert.assertNotNull(mGls);
+        mGls.deleteAllAccounts();
+
+        Assert.assertNull(mGls.getAccount(false));
+        Assert.assertNull(mGls.getAccount(true));
+
+        mGls.saveUsernameAndPassword("vespa@gmail.com", "meow",
+                                     GoogleLoginServiceConstants.FLAG_GOOGLE_ACCOUNT);
+        Assert.assertEquals("vespa@gmail.com", mGls.getAccount(false));
+        Assert.assertEquals("vespa@gmail.com", mGls.getAccount(true));
+
+        mGls.saveUsernameAndPassword("mackerel@hosted.com", "purr",
+                                     GoogleLoginServiceConstants.FLAG_HOSTED_ACCOUNT);
+        Assert.assertEquals("mackerel@hosted.com", mGls.getAccount(false));
+        Assert.assertEquals("vespa@gmail.com", mGls.getAccount(true));
+    }
+
+    public void listsEqual(String[] a, String[] b) {
+        Assert.assertEquals(a.length, b.length);
+        Arrays.sort(a);
+        Arrays.sort(b);
+        Assert.assertTrue(Arrays.equals(a, b));
+    }
+
+    public void testAuthTokens() throws Exception {
+        Assert.assertNotNull(mGls);
+        mGls.deleteAllAccounts();
+
+        Assert.assertNull(mGls.peekCredentials("vespa@example.com", "mail"));
+
+        mGls.saveUsernameAndPassword("vespa@example.com", "meow",
+                                     GoogleLoginServiceConstants.FLAG_HOSTED_ACCOUNT);
+        Assert.assertNull(mGls.peekCredentials("vespa@example.com", "mail"));
+        Assert.assertNull(mGls.peekCredentials(null, "mail"));
+
+        mGls.saveAuthToken("vespa@example.com", "mail", "1234");
+        Assert.assertEquals("1234", mGls.peekCredentials("vespa@example.com", "mail"));
+        Assert.assertEquals("1234", mGls.peekCredentials(null, "mail"));
+
+        mGls.saveUsernameAndPassword("mackerel@example.com", "purr",
+                                     GoogleLoginServiceConstants.FLAG_GOOGLE_ACCOUNT);
+        mGls.saveAuthToken("mackerel@example.com", "mail", "5678");
+        Assert.assertEquals("1234", mGls.peekCredentials(null, "mail"));
+
+        mGls.saveAuthToken("mackerel@example.com", "mail", "8765");
+        Assert.assertEquals("8765", mGls.peekCredentials("mackerel@example.com", "mail"));
+
+        GoogleLoginCredentialsResult r = mGls.blockingGetCredentials(
+                "vespa@example.com", "mail", false);
+        Assert.assertEquals("vespa@example.com", r.getAccount());
+        Assert.assertEquals("1234", r.getCredentialsString());
+        Assert.assertNull(r.getCredentialsIntent());
+
+        mGls.saveAuthToken("vespa@example.com", "cl", "abcd");
+        Assert.assertEquals("1234", mGls.peekCredentials("vespa@example.com", "mail"));
+        Assert.assertEquals("abcd", mGls.peekCredentials("vespa@example.com", "cl"));
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/GraphicsPerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/GraphicsPerformanceTests.java
new file mode 100644
index 0000000..a6c5869
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/GraphicsPerformanceTests.java
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import junit.framework.Assert;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+/**
+ * Graphics Performance Tests
+ * 
+ */
+//We don't want to run these perf tests in the continuous build.
+@Suppress 
+public class GraphicsPerformanceTests {
+    private static final String TAG = "GfxPerf";
+    public static String[] children() {
+        return new String[] {
+                // test decoding bitmaps of various sizes
+                DecodeBitmapTest.class.getName(),
+                
+                // odd-sized bitmap drawing tests
+                DrawBitmap7x7.class.getName(), 
+                DrawBitmap15x15.class.getName(),
+                DrawBitmap31x31.class.getName(), 
+                DrawBitmap63x63.class.getName(),
+                DrawBitmap127x127.class.getName(),
+                DrawBitmap319x239.class.getName(),
+                DrawBitmap319x479.class.getName(),
+                
+                // even-sized bitmap drawing tests
+                DrawBitmap8x8.class.getName(), 
+                DrawBitmap16x16.class.getName(),
+                DrawBitmap32x32.class.getName(), 
+                DrawBitmap64x64.class.getName(),
+                DrawBitmap128x128.class.getName(), 
+                DrawBitmap320x240.class.getName(),
+                DrawBitmap320x480.class.getName()};
+    }
+
+    /**
+     * Base class for all graphics tests
+     * 
+     */
+    public static abstract class GraphicsTestBase extends AndroidTestCase
+            implements PerformanceTestCase {
+        /** Target "screen" (bitmap) width and height */
+        private static final int DEFAULT_ITERATIONS = 1;
+        private static final int SCREEN_WIDTH = 320;
+        private static final int SCREEN_HEIGHT = 480;
+        
+        /** Number of iterations to pass back to harness. Subclass should override */
+        protected int mIterations = 1;
+        
+        /** Bitmap we allocate and draw to */
+        protected Bitmap mDestBitmap;
+        
+        /** Canvas of drawing routines */
+        protected Canvas mCanvas;
+        
+        /** Style and color information (uses defaults) */
+        protected Paint mPaint;
+     
+        @Override
+        public void setUp() throws Exception {
+            super.setUp();
+            // Create drawable bitmap for rendering into
+            mDestBitmap = Bitmap.createBitmap(SCREEN_WIDTH, SCREEN_HEIGHT,
+                                              Bitmap.Config.RGB_565);
+            // Set of drawing routines
+            mCanvas = new Canvas(mDestBitmap);
+            // Styles
+            mPaint = new Paint();
+            // Ask subclass for number of iterations
+            mIterations = getIterations();
+        }
+        
+        // A reasonable default
+        public int getIterations() {
+            return DEFAULT_ITERATIONS;
+        }
+
+        public boolean isPerformanceOnly() {
+            return true;
+        }
+
+        public int startPerformance(Intermediates intermediates) {
+            intermediates.setInternalIterations(mIterations * 10);
+            return 0;
+        }
+    }
+
+    /**
+     * Tests time to decode a number of sizes of images.
+     */
+    public static class DecodeBitmapTest extends GraphicsTestBase {
+        /** Number of times to run this test */
+        private static final int DECODE_ITERATIONS = 10;
+        
+        /** Used to access package bitmap images */
+        private Resources mResources;
+
+        @Override
+        public void setUp() throws Exception {
+            super.setUp();
+            
+            // For bitmap resources
+            Context context = getContext();
+            Assert.assertNotNull(context);
+            mResources = context.getResources();
+            Assert.assertNotNull(mResources); 
+        }
+        
+        @Override
+        public int getIterations() {
+            return DECODE_ITERATIONS;
+        }
+
+        public void testDecodeBitmap() {
+            for (int i = 0; i < DECODE_ITERATIONS; i++) {
+                BitmapFactory.decodeResource(mResources, R.drawable.test16x12);
+                BitmapFactory.decodeResource(mResources, R.drawable.test32x24);
+                BitmapFactory.decodeResource(mResources, R.drawable.test64x48);
+                BitmapFactory.decodeResource(mResources, R.drawable.test128x96);
+                BitmapFactory.decodeResource(mResources, R.drawable.test256x192);
+                BitmapFactory.decodeResource(mResources, R.drawable.test320x240);
+            }
+        }
+    }
+    
+    /**
+     * Base class for bitmap drawing tests
+     * 
+     */
+    public static abstract class DrawBitmapTest extends GraphicsTestBase {
+        /** Number of times to run each draw test */
+        private static final int ITERATIONS = 1000;
+        
+        /** Bitmap to draw. Allocated by subclass's createBitmap() function. */
+        private Bitmap mBitmap;
+        
+        @Override
+        public void setUp() throws Exception {
+            super.setUp();
+            
+            // Invoke subclass's method to create the bitmap
+            mBitmap = createBitmap();
+        }
+        
+        public int getIterations() {
+            return ITERATIONS;
+        }
+       
+        // Generic abstract function to create bitmap for any given subclass
+        public abstract Bitmap createBitmap();
+        
+        // Provide convenience test code for all subsequent classes. 
+        // Note: Though it would be convenient to declare all of the test*() methods here
+        // and just inherit them, our test harness doesn't support it. So we replicate
+        // a bit of code in each derived test case.
+        public void drawBitmapEven() {
+            for (int i = 0; i < ITERATIONS; i++) {
+                mCanvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint);
+            }
+        }
+
+        public void drawBitmapOdd() {
+            for (int i = 0; i < ITERATIONS; i++) {
+                mCanvas.drawBitmap(mBitmap, 1.0f, 0.0f, mPaint);
+            }
+        }
+    }
+
+
+    /**
+     * Test drawing of 7x7 image
+     */
+    public static class DrawBitmap7x7 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(7, 7, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 15x15 image
+     */
+    public static class DrawBitmap15x15 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(15, 15, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 31x31 image
+     */
+    public static class DrawBitmap31x31 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(31, 31, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 63x63 image
+     */
+    public static class DrawBitmap63x63 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(63, 63, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 127x127 image
+     */
+    public static class DrawBitmap127x127 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(127, 127, Bitmap.Config.RGB_565);
+        }
+        
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 319x239 image
+     */
+    public static class DrawBitmap319x239 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(319, 239, Bitmap.Config.RGB_565);
+        }
+        
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+    
+    /**
+     * Test drawing of 319x479 image
+     */
+    public static class DrawBitmap319x479 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(319, 479, Bitmap.Config.RGB_565);
+        }
+        
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 8x8 image
+     */
+    public static class DrawBitmap8x8 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(8, 8, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 16x16 image
+     */
+    public static class DrawBitmap16x16 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(16, 16, Bitmap.Config.RGB_565);
+        }
+        
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 32x32 image
+     */
+    public static class DrawBitmap32x32 extends DrawBitmapTest {
+        
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 64x64 image
+     */
+    public static class DrawBitmap64x64 extends DrawBitmapTest {
+
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(64, 64, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 128x128 image
+     */
+    public static class DrawBitmap128x128 extends DrawBitmapTest {
+
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(128, 128, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+
+    /**
+     * Test drawing of 320x240 image
+     */
+    public static class DrawBitmap320x240 extends DrawBitmapTest {
+
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(320, 240, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+    
+    /**
+     * Test drawing of 320x480 image
+     */
+    public static class DrawBitmap320x480 extends DrawBitmapTest {
+
+        public Bitmap createBitmap() {
+            return Bitmap.createBitmap(320, 480, Bitmap.Config.RGB_565);
+        }
+
+        public void testDrawBitmapEven() {
+            drawBitmapEven();
+        }
+        
+        public void testDrawBitmapOdd() {
+            drawBitmapOdd();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/HashMapTest.java b/tests/AndroidTests/src/com/android/unit_tests/HashMapTest.java
new file mode 100644
index 0000000..b4d15c9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/HashMapTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Set;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+public class HashMapTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    public HashMap mMap;
+    public String[] mKeys;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected void setUp() throws Exception {
+        super.setUp();
+        mMap = new HashMap();
+        mKeys = new String[ITERATIONS];
+
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            mKeys[i] = Integer.toString(i, 16);
+            mMap.put(mKeys[i], i);
+        }
+    }
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    public void testHashMapGet() {
+        int num;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+            num = (Integer) mMap.get(mKeys[i]);
+        }
+    }
+
+    public void testHashMapKeySet() {
+        Set keyset;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+            keyset = mMap.keySet();
+        }
+    }
+
+    public void testHashMapEntrySet() {
+        Set keyset;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+            keyset = mMap.entrySet();
+
+
+        }
+    }
+
+    public void testHashMapValues() {
+        Collection c;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            c = mMap.values();
+            c = mMap.values();
+            c = mMap.values();
+            c = mMap.values();
+            c = mMap.values();
+            c = mMap.values();
+            c = mMap.values();
+            c = mMap.values();
+            c = mMap.values();
+            c = mMap.values();
+
+
+        }
+    }
+
+    public void testHashMapSize() {
+        int len;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            len = mMap.size();
+            len = mMap.size();
+            len = mMap.size();
+            len = mMap.size();
+            len = mMap.size();
+            len = mMap.size();
+            len = mMap.size();
+            len = mMap.size();
+            len = mMap.size();
+            len = mMap.size();
+
+
+        }
+    }
+
+    public void testHashMapContainsValue() {
+        boolean flag;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+            flag = mMap.containsValue(i);
+
+
+        }
+    }
+
+    public void testHashMapRemove() {
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+            mMap.remove(mKeys[i]);
+        }
+    }
+
+
+    public void testHashMapClone() {
+        HashMap cMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+            cMap = (HashMap) mMap.clone();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/HashSetTest.java b/tests/AndroidTests/src/com/android/unit_tests/HashSetTest.java
new file mode 100644
index 0000000..80d3d8d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/HashSetTest.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * Implements basic performance test functionality for HashSets
+ */
+
+public class HashSetTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    public static HashSet<Integer> sSet;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        sSet = new HashSet<Integer>();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            sSet.add(i);
+        }
+    }
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    /**
+     * 
+     * Tests performance for the HashSet method Add(Object arg 0)
+     * 
+     */
+
+    @SuppressWarnings("unchecked")
+    public void testHashSetAdd() {
+        HashSet set = new HashSet();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+        }
+
+    }
+
+    /**
+     * 
+     * Tests performance of HashSet method contains(Object arg 0)
+     * 
+     */
+
+    public void testHashSetContains() {
+        Integer index = new Integer(500);
+        boolean flag;
+        HashSet set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+        }
+    }
+
+    /**
+     * 
+     * Tests performance of HashSet method size()
+     * 
+     */
+
+    public void testHashSetSize() {
+        int num;
+        HashSet set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            num = set.size();
+            num = set.size();
+            num = set.size();
+            num = set.size();
+            num = set.size();
+            num = set.size();
+            num = set.size();
+            num = set.size();
+            num = set.size();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance of the HashSet method -iterator()
+     * 
+     */
+
+    public void testHashSetIterator() {
+        Iterator iterator;
+        HashSet set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the HashSet method Remove(Object arg 0)
+     * 
+     */
+
+    @SuppressWarnings("unchecked")
+    public void testHashSetRemove() {
+        HashSet set = new HashSet(sSet);
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the HashSet method isEmpty(Object arg 0)
+     * 
+     */
+
+    public void testHashSetIsEmpty() {
+        HashSet set = sSet;
+        boolean flag;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+            flag = set.isEmpty();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the HashSet method clone()
+     * 
+     */
+
+    public void testHashSetClone() {
+        HashSet hSet = sSet;
+        Object set;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            set = hSet.clone();
+            set = hSet.clone();
+            set = hSet.clone();
+            set = hSet.clone();
+            set = hSet.clone();
+            set = hSet.clone();
+            set = hSet.clone();
+            set = hSet.clone();
+            set = hSet.clone();
+            set = hSet.clone();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/HashtableTest.java b/tests/AndroidTests/src/com/android/unit_tests/HashtableTest.java
new file mode 100644
index 0000000..42bec11
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/HashtableTest.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.Enumeration;
+
+/**
+ * Implements basic performance test functionality for java.util.Hashtable
+ */
+
+public class HashtableTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    public Hashtable<String, Integer> sTable;
+    public String[] sKeys;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected void setUp() throws Exception {
+        super.setUp();
+        sTable = new Hashtable();
+        sKeys = new String[ITERATIONS];
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            sKeys[i] = Integer.toString(i, 16);
+            sTable.put(sKeys[i], i);
+        }
+    }
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testHashtablePut() {
+        Hashtable hTable = new Hashtable();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            hTable.put(i, i);
+            hTable.put(i, i);
+            hTable.put(i, i);
+            hTable.put(i, i);
+            hTable.put(i, i);
+            hTable.put(i, i);
+            hTable.put(i, i);
+            hTable.put(i, i);
+            hTable.put(i, i);
+            hTable.put(i, i);
+        }
+    }
+
+    public void testHashtableGet() {
+        int value;
+        String[] keys = sKeys;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+            value = hTable.get(keys[i]);
+        }
+    }
+
+    public void testHashtablekeyset() {
+        Set keyset;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+            keyset = hTable.keySet();
+        }
+    }
+
+    /**
+     * 
+     */
+
+    public void testHashtableEntrySet() {
+        Set keyset;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+            keyset = hTable.entrySet();
+        }
+    }
+
+    public void testHashtableSize() {
+        int len;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            len = hTable.size();
+            len = hTable.size();
+            len = hTable.size();
+            len = hTable.size();
+            len = hTable.size();
+            len = hTable.size();
+            len = hTable.size();
+            len = hTable.size();
+            len = hTable.size();
+            len = hTable.size();
+        }
+    }
+
+    public void testHashtableContainsValue() {
+        boolean flag;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+            flag = hTable.containsValue(i);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testHashtableRemove() {
+        Hashtable<String, Integer> hTable = new Hashtable(sTable);
+        String[] keys = sKeys;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+            hTable.remove(keys[i]);
+        }
+    }
+
+    public void testHashtableContains() {
+        Hashtable<String, Integer> hTable = sTable;
+        boolean flag;
+
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+            flag = hTable.contains(i);
+        }
+    }
+
+    public void testHashtableContainsKey() {
+        Hashtable<String, Integer> hTable = sTable;
+        boolean flag;
+
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+            flag = hTable.containsKey(i);
+        }
+    }
+
+    public void testHashtableIsEmpty() {
+        Hashtable<String, Integer> hTable = sTable;
+        boolean flag;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+            flag = hTable.isEmpty();
+        }
+    }
+
+    public void testHashtableKeys() {
+        Hashtable<String, Integer> hTable = sTable;
+        Enumeration<String> keys;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            keys = hTable.keys();
+            keys = hTable.keys();
+            keys = hTable.keys();
+            keys = hTable.keys();
+            keys = hTable.keys();
+            keys = hTable.keys();
+            keys = hTable.keys();
+            keys = hTable.keys();
+            keys = hTable.keys();
+            keys = hTable.keys();
+        }
+    }
+
+    public void testHashtableElements() {
+        Hashtable<String, Integer> hTable = sTable;
+        Enumeration<Integer> elements;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            elements = hTable.elements();
+            elements = hTable.elements();
+            elements = hTable.elements();
+            elements = hTable.elements();
+            elements = hTable.elements();
+            elements = hTable.elements();
+            elements = hTable.elements();
+            elements = hTable.elements();
+            elements = hTable.elements();
+            elements = hTable.elements();
+        }
+    }
+
+    public void testHashtableHashCode() {
+        int index;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+            index = hTable.hashCode();
+        }
+    }
+
+    public void testHashtableEquals() {
+        boolean flag;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+            flag = hTable.equals(hTable);
+        }
+    }
+
+    public void testHashtableToString() {
+        String str;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            str = hTable.toString();
+            str = hTable.toString();
+            str = hTable.toString();
+            str = hTable.toString();
+            str = hTable.toString();
+            str = hTable.toString();
+            str = hTable.toString();
+            str = hTable.toString();
+            str = hTable.toString();
+            str = hTable.toString();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testHashtablePutAll() {
+        Hashtable<String, Integer> hTable = new Hashtable();
+        Hashtable<String, Integer> hTable1 = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+            hTable.putAll(hTable1);
+        }
+    }
+
+    /**
+     * 
+     * clone() returns a Hashtable .. It should return Object as per the
+     * specification.
+     * 
+     */
+
+    public void testHashtableClone() {
+        Hashtable hashTable;
+        Hashtable<String, Integer> hTable = sTable;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+            hashTable = (Hashtable) hTable.clone();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/HeapTest.java b/tests/AndroidTests/src/com/android/unit_tests/HeapTest.java
new file mode 100644
index 0000000..d21e6a3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/HeapTest.java
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.test.suitebuilder.annotation.Suppress;
+import dalvik.system.VMRuntime;
+import junit.framework.TestCase;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.LinkedList;
+import java.util.Random;
+
+
+public class HeapTest extends TestCase {
+
+    private static final String TAG = "HeapTest";
+
+    /**
+     * Returns a WeakReference to an object that has no
+     * other references.  This is done in a separate method
+     * to ensure that the Object's address isn't sitting in
+     * a stale local register.
+     */
+    private WeakReference<Object> newRef() {
+        return new WeakReference<Object>(new Object());
+    }
+
+    /**
+     * Allocates the specified number of bytes. This is done in a separate method
+     * to ensure that the Object's address isn't sitting in a stale local register.
+     */
+    private void allocateMemory(int size) {
+        byte[] b = new byte[size];
+    }
+
+    @MediumTest
+    public void testMinimumHeapSize() throws Exception {
+        VMRuntime r = VMRuntime.getRuntime();
+        final boolean RUN_FLAKY = false;
+
+        long origSize = r.getMinimumHeapSize();
+        if (RUN_FLAKY) {
+            /* Check that the default value is zero.  This will break if anyone
+             * in this process sets the minimum heap size to a positive value
+             * before calling this test.
+             */
+            assertTrue(origSize == 0);
+        }
+
+        long size = 4 * 1024 * 1024;
+        long oldSize = r.setMinimumHeapSize(size);
+        assertTrue(oldSize == origSize);
+
+        long newSize = r.getMinimumHeapSize();
+        /* This will fail if the maximum heap size (-Xmx) is smaller than 4MB.
+         */
+        assertTrue(newSize == size);
+
+        /* Make sure that getting the size doesn't change anything.
+         */
+        newSize = r.getMinimumHeapSize();
+        assertTrue(newSize == size);
+
+        /* This test is flaky; if the heap is already large and fragmented,
+         * it can fail.  It can also fail if another thread causes a GC
+         * at the wrong time.
+         */
+        if (RUN_FLAKY) {
+            /* Increase the minimum size, allocate a big object, and make sure that
+             * a GC didn't happen.
+             */
+            WeakReference ref = newRef();
+            assertNotNull(ref.get());
+
+            r.setMinimumHeapSize(8 * 1024 * 1024);
+            allocateMemory(4 * 1024 * 1024);
+
+            /* If a GC happened, this reference will be null.
+             */
+            assertNotNull(ref.get());
+        }
+
+        /* Restore the original setting.
+         */
+        r.setMinimumHeapSize(origSize);
+        newSize = r.getMinimumHeapSize();
+        assertTrue(newSize == origSize);
+
+        /* Clean up any large stuff we've allocated,
+         * and re-establish the normal utilization ratio.
+         */
+        Runtime.getRuntime().gc();
+    }
+
+    private static void makeRefs(Object objects[], SoftReference<Object> refs[]) {
+        for (int i = 0; i < objects.length; i++) {
+            objects[i] = (Object) new byte[8 * 1024];
+            refs[i] = new SoftReference<Object>(objects[i]);
+        }
+    }
+
+    private static <T> int checkRefs(SoftReference<T> refs[], int last) {
+        int i;
+        int numCleared = 0;
+        for (i = 0; i < refs.length; i++) {
+            Object o = refs[i].get();
+            if (o == null) {
+                numCleared++;
+            }
+        }
+        if (numCleared != last) {
+            Log.i(TAG, "****** " + numCleared + "/" + i + " cleared ******");
+        }
+        return numCleared;
+    }
+
+    private static void clearRefs(Object objects[], int skip) {
+        for (int i = 0; i < objects.length; i += skip) {
+            objects[i] = null;
+        }
+    }
+
+    private static void clearRefs(Object objects[]) {
+        clearRefs(objects, 1);
+    }
+
+    private static <T> void checkRefs(T objects[], SoftReference<T> refs[]) {
+        boolean ok = true;
+
+        for (int i = 0; i < objects.length; i++) {
+            if (refs[i].get() != objects[i]) {
+                ok = false;
+            }
+        }
+        if (!ok) {
+            throw new RuntimeException("Test failed: soft refs not cleared");
+        }
+    }
+
+    @MediumTest
+    public void testGcSoftRefs() throws Exception {
+        final int NUM_REFS = 128;
+
+        Object objects[] = new Object[NUM_REFS];
+        SoftReference<Object> refs[] = new SoftReference[objects.length];
+
+        /* Create a bunch of objects and a parallel array
+         * of SoftReferences.
+         */
+        makeRefs(objects, refs);
+        Runtime.getRuntime().gc();
+
+        /* Let go of some of the hard references to the objects so that
+         * the references can be cleared.
+         */
+        clearRefs(objects, 3);
+
+        /* Collect all softly-reachable objects.
+         */
+        VMRuntime.getRuntime().gcSoftReferences();
+        Runtime.getRuntime().runFinalization();
+
+        /* Make sure that the objects were collected.
+         */
+        checkRefs(objects, refs);
+
+        /* Remove more hard references and re-check.
+         */
+        clearRefs(objects, 2);
+        VMRuntime.getRuntime().gcSoftReferences();
+        Runtime.getRuntime().runFinalization();
+        checkRefs(objects, refs);
+
+        /* Remove the rest of the references and re-check.
+         */
+        /* Remove more hard references and re-check.
+         */
+        clearRefs(objects);
+        VMRuntime.getRuntime().gcSoftReferences();
+        Runtime.getRuntime().runFinalization();
+        checkRefs(objects, refs);
+    }
+
+    public void xxtestSoftRefPartialClean() throws Exception {
+        final int NUM_REFS = 128;
+
+        Object objects[] = new Object[NUM_REFS];
+        SoftReference<Object> refs[] = new SoftReference[objects.length];
+
+        /* Create a bunch of objects and a parallel array
+        * of SoftReferences.
+        */
+        makeRefs(objects, refs);
+        Runtime.getRuntime().gc();
+
+        /* Let go of the hard references to the objects so that
+        * the references can be cleared.
+        */
+        clearRefs(objects);
+
+        /* Start creating a bunch of temporary and permanent objects
+        * to drive GC.
+        */
+        final int NUM_OBJECTS = 64 * 1024;
+        Object junk[] = new Object[NUM_OBJECTS];
+        Random random = new Random();
+
+        int i = 0;
+        int mod = 0;
+        int totalSize = 0;
+        int cleared = -1;
+        while (i < junk.length && totalSize < 8 * 1024 * 1024) {
+            int r = random.nextInt(64 * 1024) + 128;
+            Object o = (Object) new byte[r];
+            if (++mod % 16 == 0) {
+                junk[i++] = o;
+                totalSize += r * 4;
+            }
+            cleared = checkRefs(refs, cleared);
+        }
+    }
+
+    private static void makeRefs(Object objects[], WeakReference<Object> refs[]) {
+        for (int i = 0; i < objects.length; i++) {
+            objects[i] = new Object();
+            refs[i] = new WeakReference<Object>(objects[i]);
+        }
+    }
+
+    private static <T> void checkRefs(T objects[], WeakReference<T> refs[]) {
+        boolean ok = true;
+
+        for (int i = 0; i < objects.length; i++) {
+            if (refs[i].get() != objects[i]) {
+                ok = false;
+            }
+        }
+        if (!ok) {
+            throw new RuntimeException("Test failed: " +
+                    "weak refs not cleared");
+        }
+    }
+
+    @MediumTest
+    public void testWeakRefs() throws Exception {
+        final int NUM_REFS = 16;
+
+        Object objects[] = new Object[NUM_REFS];
+        WeakReference<Object> refs[] = new WeakReference[objects.length];
+
+        /* Create a bunch of objects and a parallel array
+        * of WeakReferences.
+        */
+        makeRefs(objects, refs);
+        Runtime.getRuntime().gc();
+        checkRefs(objects, refs);
+
+        /* Clear out every other strong reference.
+        */
+        for (int i = 0; i < objects.length; i += 2) {
+            objects[i] = null;
+        }
+        Runtime.getRuntime().gc();
+        checkRefs(objects, refs);
+
+        /* Clear out the rest of them.
+        */
+        for (int i = 0; i < objects.length; i++) {
+            objects[i] = null;
+        }
+        Runtime.getRuntime().gc();
+        checkRefs(objects, refs);
+    }
+
+    private static void makeRefs(Object objects[], PhantomReference<Object> refs[],
+            ReferenceQueue<Object> queue) {
+        for (int i = 0; i < objects.length; i++) {
+            objects[i] = new Object();
+            refs[i] = new PhantomReference<Object>(objects[i], queue);
+        }
+    }
+
+    static <T> void checkRefs(T objects[], PhantomReference<T> refs[],
+            ReferenceQueue<T> queue) {
+        boolean ok = true;
+
+        /* Make sure that the reference that should be on
+        * the queue are marked as enqueued.  Once we
+        * pull them off the queue, they will no longer
+        * be marked as enqueued.
+        */
+        for (int i = 0; i < objects.length; i++) {
+            if (objects[i] == null && refs[i] != null) {
+                if (!refs[i].isEnqueued()) {
+                    ok = false;
+                }
+            }
+        }
+        if (!ok) {
+            throw new RuntimeException("Test failed: " +
+                    "phantom refs not marked as enqueued");
+        }
+
+        /* Make sure that all of the references on the queue
+        * are supposed to be there.
+        */
+        PhantomReference<T> ref;
+        while ((ref = (PhantomReference<T>) queue.poll()) != null) {
+            /* Find the list index that corresponds to this reference.
+            */
+            int i;
+            for (i = 0; i < objects.length; i++) {
+                if (refs[i] == ref) {
+                    break;
+                }
+            }
+            if (i == objects.length) {
+                throw new RuntimeException("Test failed: " +
+                        "unexpected ref on queue");
+            }
+            if (objects[i] != null) {
+                throw new RuntimeException("Test failed: " +
+                        "reference enqueued for strongly-reachable " +
+                        "object");
+            }
+            refs[i] = null;
+
+            /* TODO: clear doesn't do much, since we're losing the
+            * strong ref to the ref object anyway.  move the ref
+            * into another list.
+            */
+            ref.clear();
+        }
+
+        /* We've visited all of the enqueued references.
+        * Make sure that there aren't any other references
+        * that should have been enqueued.
+        *
+        * NOTE: there is a race condition here;  this assumes
+        * that the VM has serviced all outstanding reference
+        * enqueue() calls.
+        */
+        for (int i = 0; i < objects.length; i++) {
+            if (objects[i] == null && refs[i] != null) {
+//                System.out.println("HeapTest/PhantomRefs: refs[" + i +
+//                        "] should be enqueued");
+                ok = false;
+            }
+        }
+        if (!ok) {
+            throw new RuntimeException("Test failed: " +
+                    "phantom refs not enqueued");
+        }
+    }
+
+    @MediumTest
+    public void testPhantomRefs() throws Exception {
+        final int NUM_REFS = 16;
+
+        Object objects[] = new Object[NUM_REFS];
+        PhantomReference<Object> refs[] = new PhantomReference[objects.length];
+        ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+
+        /* Create a bunch of objects and a parallel array
+        * of PhantomReferences.
+        */
+        makeRefs(objects, refs, queue);
+        Runtime.getRuntime().gc();
+        checkRefs(objects, refs, queue);
+
+        /* Clear out every other strong reference.
+        */
+        for (int i = 0; i < objects.length; i += 2) {
+            objects[i] = null;
+        }
+        // System.out.println("HeapTest/PhantomRefs: cleared evens");
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+        checkRefs(objects, refs, queue);
+
+        /* Clear out the rest of them.
+        */
+        for (int i = 0; i < objects.length; i++) {
+            objects[i] = null;
+        }
+        // System.out.println("HeapTest/PhantomRefs: cleared all");
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+        checkRefs(objects, refs, queue);
+    }
+
+    private static int sNumFinalized = 0;
+    private static final Object sLock = new Object();
+
+    private static class FinalizableObject {
+        protected void finalize() {
+            // System.out.println("gc from finalize()");
+            Runtime.getRuntime().gc();
+            synchronized (sLock) {
+                sNumFinalized++;
+            }
+        }
+    }
+
+    private static void makeRefs(FinalizableObject objects[],
+            WeakReference<FinalizableObject> refs[]) {
+        for (int i = 0; i < objects.length; i++) {
+            objects[i] = new FinalizableObject();
+            refs[i] = new WeakReference<FinalizableObject>(objects[i]);
+        }
+    }
+
+    @LargeTest
+    public void testWeakRefsAndFinalizers() throws Exception {
+        final int NUM_REFS = 16;
+
+        FinalizableObject objects[] = new FinalizableObject[NUM_REFS];
+        WeakReference<FinalizableObject> refs[] = new WeakReference[objects.length];
+        int numCleared;
+
+        /* Create a bunch of objects and a parallel array
+        * of WeakReferences.
+        */
+        makeRefs(objects, refs);
+        Runtime.getRuntime().gc();
+        checkRefs(objects, refs);
+
+        /* Clear out every other strong reference.
+        */
+        sNumFinalized = 0;
+        numCleared = 0;
+        for (int i = 0; i < objects.length; i += 2) {
+            objects[i] = null;
+            numCleared++;
+        }
+        // System.out.println("HeapTest/WeakRefsAndFinalizers: cleared evens");
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+        checkRefs(objects, refs);
+        if (sNumFinalized != numCleared) {
+            throw new RuntimeException("Test failed: " +
+                    "expected " + numCleared + " finalizations, saw " +
+                    sNumFinalized);
+        }
+
+        /* Clear out the rest of them.
+        */
+        sNumFinalized = 0;
+        numCleared = 0;
+        for (int i = 0; i < objects.length; i++) {
+            if (objects[i] != null) {
+                objects[i] = null;
+                numCleared++;
+            }
+        }
+        // System.out.println("HeapTest/WeakRefsAndFinalizers: cleared all");
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+        checkRefs(objects, refs);
+        if (sNumFinalized != numCleared) {
+            throw new RuntimeException("Test failed: " +
+                    "expected " + numCleared + " finalizations, saw " +
+                    sNumFinalized);
+        }
+    }
+
+    @MediumTest
+    public void testOomeLarge() throws Exception {
+        /* Just shy of the typical max heap size so that it will actually
+         * try to allocate it instead of short-circuiting.
+         */
+        final int SIXTEEN_MB = (16 * 1024 * 1024 - 32);
+
+        Boolean sawEx = false;
+        byte a[];
+
+        try {
+            a = new byte[SIXTEEN_MB];
+        } catch (OutOfMemoryError oom) {
+            //Log.i(TAG, "HeapTest/OomeLarge caught " + oom);
+            sawEx = true;
+        }
+
+        if (!sawEx) {
+            throw new RuntimeException("Test failed: " +
+                    "OutOfMemoryError not thrown");
+        }
+    }
+
+    //See bug 1308253 for reasons.
+    @Suppress
+    public void disableTestOomeSmall() throws Exception {
+        final int SIXTEEN_MB = (16 * 1024 * 1024);
+        final int LINK_SIZE = 6 * 4; // estimated size of a LinkedList's node
+
+        Boolean sawEx = false;
+
+        LinkedList<Object> list = new LinkedList<Object>();
+
+        /* Allocate progressively smaller objects to fill up the entire heap.
+         */
+        int objSize = 1 * 1024 * 1024;
+        while (objSize >= LINK_SIZE) {
+            try {
+                for (int i = 0; i < SIXTEEN_MB / objSize; i++) {
+                    list.add((Object)new byte[objSize]);
+                }
+            } catch (OutOfMemoryError oom) {
+                sawEx = true;
+            }
+
+            if (!sawEx) {
+                throw new RuntimeException("Test failed: " +
+                        "OutOfMemoryError not thrown while filling heap");
+            }
+            sawEx = false;
+
+            objSize = (objSize * 4) / 5;
+        }
+    }
+
+    @SmallTest
+    public void testExternalOomeLarge() {
+        /* Just shy of the typical max heap size so that it will actually
+         * try to allocate it instead of short-circuiting.
+         */
+        final int HUGE_SIZE = (16 * 1024 * 1024 - 32);
+
+        assertFalse(VMRuntime.getRuntime().trackExternalAllocation(HUGE_SIZE));
+    }
+
+    /**
+     * "Allocates" external memory in progressively smaller chunks until there's
+     * only roughly 16 bytes left.
+     *
+     * @return the number of bytes allocated
+     */
+    private long allocateMaxExternal() {
+        final VMRuntime runtime = VMRuntime.getRuntime();
+        final int SIXTEEN_MB = (16 * 1024 * 1024);
+        final int MIN_SIZE = 16;
+        long totalAllocated = 0;
+        boolean success;
+
+        success = false;
+        try {
+            /* "Allocate" progressively smaller chunks to "fill up" the entire heap.
+             */
+            int objSize = 1 * 1024 * 1024;
+            while (objSize >= MIN_SIZE) {
+                boolean sawFailure = false;
+                for (int i = 0; i < SIXTEEN_MB / objSize; i++) {
+                    if (runtime.trackExternalAllocation(objSize)) {
+                        totalAllocated += objSize;
+                    } else {
+                        sawFailure = true;
+                        break;
+                    }
+                }
+
+                if (!sawFailure) {
+                    throw new RuntimeException("Test failed: " +
+                            "no failure while filling heap");
+                }
+
+                objSize = (objSize * 4) / 5;
+            }
+            success = true;
+        } finally {
+            if (!success) {
+                runtime.trackExternalFree(totalAllocated);
+                totalAllocated = 0;
+            }
+        }
+        return totalAllocated;
+    }
+
+    public void xxtest00ExternalOomeSmall() {
+        VMRuntime.getRuntime().trackExternalFree(allocateMaxExternal());
+    }
+
+    /**
+     * Allocates as much external memory as possible, then allocates from the heap
+     * until an OOME is caught.
+     *
+     * It's nice to run this test while the real heap is small, hence the '00' in its
+     * name to force it to run before testOomeSmall().
+     */
+    public void xxtest00CombinedOomeSmall() {
+        long totalAllocated = 0;
+        boolean sawEx = false;
+        try {
+            totalAllocated = allocateMaxExternal();
+            LinkedList<Object> list = new LinkedList<Object>();
+            try {
+                while (true) {
+                    list.add((Object)new byte[8192]);
+                }
+                /*NOTREACHED*/
+            } catch (OutOfMemoryError oom) {
+                sawEx = true;
+            }
+        } finally {
+            VMRuntime.getRuntime().trackExternalFree(totalAllocated);
+        }
+        assertTrue(sawEx);
+    }
+
+    //TODO: test external alloc debugging/inspection
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java b/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java
new file mode 100644
index 0000000..27da4f1
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/HtmlTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.graphics.Typeface;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.*;
+import android.text.style.*;
+
+import junit.framework.TestCase;
+
+/**
+ * HtmlTest tests the Spanned-to-HTML converter
+ */
+public class HtmlTest extends TestCase {
+    @MediumTest
+    public void testColor() throws Exception {
+        Spanned s;
+        ForegroundColorSpan[] colors;
+
+        s = Html.fromHtml("<font color=\"#00FF00\">something</font>");
+        colors = s.getSpans(0, s.length(), ForegroundColorSpan.class);
+        assertEquals(colors[0].getForegroundColor(), 0xFF00FF00);
+
+        s = Html.fromHtml("<font color=\"navy\">something</font>");
+        colors = s.getSpans(0, s.length(), ForegroundColorSpan.class);
+        assertEquals(colors[0].getForegroundColor(), 0xFF000080);
+
+        s = Html.fromHtml("<font color=\"gibberish\">something</font>");
+        colors = s.getSpans(0, s.length(), ForegroundColorSpan.class);
+        assertEquals(colors.length, 0);
+    }
+
+    @SmallTest
+    public void testParagraphs() throws Exception {
+        SpannableString s;
+
+        s = new SpannableString("Hello world");
+        assertEquals(Html.toHtml(s), "<p>Hello world</p>\n");
+
+        s = new SpannableString("Hello world\nor something");
+        assertEquals(Html.toHtml(s), "<p>Hello world<br>\nor something</p>\n");
+
+        s = new SpannableString("Hello world\n\nor something");
+        assertEquals(Html.toHtml(s), "<p>Hello world</p>\n<p>or something</p>\n");
+
+        s = new SpannableString("Hello world\n\n\nor something");
+        assertEquals(Html.toHtml(s), "<p>Hello world<br></p>\n<p>or something</p>\n");
+
+        assertEquals("foo\nbar", Html.fromHtml("foo<br>bar").toString());
+        assertEquals("foo\nbar", Html.fromHtml("foo<br>\nbar").toString());
+        assertEquals("foo\nbar", Html.fromHtml("foo<br>\n \nbar").toString());
+    }
+
+    @SmallTest
+    public void testBlockquote() throws Exception {
+        SpannableString s;
+
+        s = new SpannableString("Hello world");
+        s.setSpan(new QuoteSpan(), 0, s.length(), Spannable.SPAN_PARAGRAPH);
+        assertEquals(Html.toHtml(s), "<blockquote><p>Hello world</p>\n</blockquote>\n");
+
+        s = new SpannableString("Hello\n\nworld");
+        s.setSpan(new QuoteSpan(), 0, 7, Spannable.SPAN_PARAGRAPH);
+        assertEquals(Html.toHtml(s), "<blockquote><p>Hello</p>\n</blockquote>\n<p>world</p>\n");
+    }
+
+    @SmallTest
+    public void testEntities() throws Exception {
+        SpannableString s;
+
+        s = new SpannableString("Hello <&> world");
+        assertEquals(Html.toHtml(s), "<p>Hello &lt;&amp;&gt; world</p>\n");
+
+        s = new SpannableString("Hello \u03D5 world");
+        assertEquals(Html.toHtml(s), "<p>Hello &#981; world</p>\n");
+
+        s = new SpannableString("Hello  world");
+        assertEquals(Html.toHtml(s), "<p>Hello&nbsp; world</p>\n");
+    }
+
+    @SmallTest
+    public void testMarkup() throws Exception {
+        SpannableString s;
+
+        s = new SpannableString("Hello bold world");
+        s.setSpan(new StyleSpan(Typeface.BOLD), 6, s.length() - 6,
+                  Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        assertEquals(Html.toHtml(s), "<p>Hello <b>bold</b> world</p>\n");
+
+        s = new SpannableString("Hello italic world");
+        s.setSpan(new StyleSpan(Typeface.ITALIC), 6, s.length() - 6,
+                  Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        assertEquals(Html.toHtml(s), "<p>Hello <i>italic</i> world</p>\n");
+
+        s = new SpannableString("Hello monospace world");
+        s.setSpan(new TypefaceSpan("monospace"), 6, s.length() - 6,
+                  Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        assertEquals(Html.toHtml(s), "<p>Hello <tt>monospace</tt> world</p>\n");
+
+        s = new SpannableString("Hello superscript world");
+        s.setSpan(new SuperscriptSpan(), 6, s.length() - 6,
+                  Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        assertEquals(Html.toHtml(s), "<p>Hello <sup>superscript</sup> world</p>\n");
+
+        s = new SpannableString("Hello subscript world");
+        s.setSpan(new SubscriptSpan(), 6, s.length() - 6,
+                  Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        assertEquals(Html.toHtml(s), "<p>Hello <sub>subscript</sub> world</p>\n");
+
+        s = new SpannableString("Hello underline world");
+        s.setSpan(new UnderlineSpan(), 6, s.length() - 6,
+                  Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        assertEquals(Html.toHtml(s), "<p>Hello <u>underline</u> world</p>\n");
+
+        s = new SpannableString("Hello struck world");
+        s.setSpan(new StrikethroughSpan(), 6, s.length() - 6,
+                  Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        assertEquals(Html.toHtml(s), "<p>Hello <strike>struck</strike> world</p>\n");
+
+        s = new SpannableString("Hello linky world");
+        s.setSpan(new URLSpan("http://www.google.com"), 6, s.length() - 6,
+                  Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+        assertEquals(Html.toHtml(s),
+                     "<p>Hello <a href=\"http://www.google.com\">linky</a> world</p>\n");
+    }
+
+    @SmallTest
+    public void testImg() throws Exception {
+        Spanned s;
+
+        s = Html.fromHtml("yes<img src=\"http://example.com/foo.gif\">no");
+
+        assertEquals("<p>yes<img src=\"http://example.com/foo.gif\">no</p>\n",
+                     Html.toHtml(s));
+    }
+
+    @SmallTest
+    public void testUtf8() throws Exception {
+        Spanned s;
+
+        s = Html.fromHtml("<p>\u0124\u00eb\u0142\u0142o, world!</p>");
+        assertEquals("<p>&#292;&#235;&#322;&#322;o, world!</p>\n", Html.toHtml(s));
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java b/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java
new file mode 100644
index 0000000..d7c9d60
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import java.util.Map;
+
+public class InflateTest extends AndroidTestCase implements PerformanceTestCase {
+    private LayoutInflater mInflater;
+    private Resources mResources;
+    private View mView;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mInflater = LayoutInflater.from(mContext);
+        mResources = mContext.getResources();
+
+        // to try to make things consistent, before doing timing
+        // do an initial instantiation of the layout and then clear
+        // out the layout cache.
+//            mInflater.inflate(mResId, null, null);
+//            mResources.flushLayoutCache();
+    }
+
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        return 0;
+    }
+
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+    public void inflateTest(int resourceId) {
+        mView = mInflater.inflate(resourceId, null);
+        mResources.flushLayoutCache();
+    }
+
+    public void inflateCachedTest(int resourceId) {
+        // Make sure this layout is in the cache.
+        mInflater.inflate(resourceId, null);
+
+        mInflater.inflate(resourceId, null);
+    }
+
+    @SmallTest
+    public void testLayout1() throws Exception {
+        inflateTest(R.layout.layout_one);
+    }
+
+    @SmallTest
+    public void testLayout2() throws Exception {
+        inflateTest(R.layout.layout_two);
+    }
+
+    @SmallTest
+    public void testLayout3() throws Exception {
+        inflateTest(R.layout.layout_three);
+    }
+
+    @SmallTest
+    public void testLayout4() throws Exception {
+        inflateTest(R.layout.layout_four);
+    }
+
+    @SmallTest
+    public void testLayout5() throws Exception {
+        inflateTest(R.layout.layout_five);
+    }
+
+    @SmallTest
+    public void testLayout6() throws Exception {
+        inflateTest(R.layout.layout_six);
+    }
+
+    @SmallTest
+    public void testCachedLayout1() throws Exception {
+        inflateCachedTest(R.layout.layout_one);
+    }
+
+    @SmallTest
+    public void testCachedLayout2() throws Exception {
+        inflateCachedTest(R.layout.layout_two);
+    }
+
+    @SmallTest
+    public void testCachedLayout3() throws Exception {
+        inflateCachedTest(R.layout.layout_three);
+    }
+
+    @SmallTest
+    public void testCachedLayout4() throws Exception {
+        inflateCachedTest(R.layout.layout_four);
+    }
+
+    @SmallTest
+    public void testCachedLayout5() throws Exception {
+        inflateCachedTest(R.layout.layout_five);
+    }
+
+    @SmallTest
+    public void testCachedLayout6() throws Exception {
+        inflateCachedTest(R.layout.layout_six);
+    }
+
+//    public void testLayoutTag() throws Exception {
+//        public void setUp
+//        (Context
+//        context){
+//        setUp(context, R.layout.layout_tag);
+//    }
+//        public void run
+//        ()
+//        {
+//            super.run();
+//            if (!"MyTag".equals(mView.getTag())) {
+//                throw new RuntimeException("Incorrect tag: " + mView.getTag());
+//            }
+//        }
+//    }
+
+    public static class ViewOne extends View {
+        public ViewOne(Context context) {
+            super(context);
+        }
+
+        public ViewOne(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java b/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java
new file mode 100644
index 0000000..1f82df8
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+
+public class InstanceofTest extends TestCase {
+
+    protected A mA;
+    protected ChildOfAOne mOne;
+    protected ChildOfAOne mTwo;
+    protected ChildOfAOne mThree;
+    protected ChildOfAOne mFour;
+    protected ChildOfAFive mFive;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mA = new A();
+        mOne = new ChildOfAOne();
+        mTwo = new ChildOfATwo();
+        mThree = new ChildOfAThree();
+        mFour = new ChildOfAFour();
+        mFive = new ChildOfAFive();
+    }
+
+
+    @MediumTest
+    public void testNoInterface() throws Exception {
+        A a = mA;
+        for (int i = 0; i < 100000; i++) {
+            assertFalse("m_a should not be a ChildOfAFive", a instanceof ChildOfAFive);
+        }
+    }
+
+    @MediumTest
+    public void testDerivedOne() throws Exception {
+        InterfaceOne one = mOne;
+        for (int i = 0; i < 100000; i++) {
+            assertFalse("m_one should not be a ChildOfAFive", one instanceof ChildOfAFive);
+        }
+    }
+
+    @MediumTest
+    public void testDerivedTwo() throws Exception {
+        InterfaceTwo two = mTwo;
+        for (int i = 0; i < 100000; i++) {
+            assertFalse("m_two should not be a ChildOfAFive", two instanceof ChildOfAFive);
+        }
+    }
+
+    @MediumTest
+    public void testDerivedThree() throws Exception {
+        InterfaceThree three = mThree;
+        for (int i = 0; i < 100000; i++) {
+            assertFalse("m_three should not be a ChildOfAFive", three instanceof ChildOfAFive);
+        }
+    }
+
+    @MediumTest
+    public void testDerivedFour() throws Exception {
+        InterfaceFour four = mFour;
+        for (int i = 0; i < 100000; i++) {
+            assertFalse("m_four should not be a ChildOfAFive", four instanceof ChildOfAFive);
+        }
+    }
+
+    @MediumTest
+    public void testSuccessClass() throws Exception {
+        ChildOfAOne five = mFive;
+        for (int i = 0; i < 100000; i++) {
+            assertTrue("m_five is suppose to be a ChildOfAFive", five instanceof ChildOfAFive);
+        }
+    }
+
+    @MediumTest
+    public void testSuccessInterface() throws Exception {
+        ChildOfAFive five = mFive;
+        for (int i = 0; i < 100000; i++) {
+            assertTrue("m_five is suppose to be a InterfaceFour", five instanceof InterfaceFour);
+        }
+    }
+
+    @MediumTest
+    public void testFailInterface() throws Exception {
+        InterfaceOne one = mFive;
+        for (int i = 0; i < 100000; i++) {
+            assertFalse("m_five does not implement InterfaceFive", one instanceof InterfaceFive);
+        }
+    }
+
+    private interface InterfaceOne {
+    }
+
+    private interface InterfaceTwo {
+    }
+
+    private interface InterfaceThree {
+    }
+
+    private interface InterfaceFour {
+    }
+
+    private interface InterfaceFive {
+    }
+
+    private static class A {
+    }
+
+    private static class ChildOfAOne extends A implements InterfaceOne, InterfaceTwo, InterfaceThree, InterfaceFour {
+    }
+
+    private static class ChildOfATwo extends ChildOfAOne {
+    }
+
+    private static class ChildOfAThree extends ChildOfATwo {
+    }
+
+    private static class ChildOfAFour extends ChildOfAThree {
+    }
+
+    private static class ChildOfAFive extends ChildOfAFour {
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java
new file mode 100644
index 0000000..e778d53
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+/**
+ * 
+ */
+public class JavaPerformanceTests {
+
+    public static String[] children() {
+        return new String[] {
+                StringTest.class.getName(),
+                HashMapTest.class.getName(),
+                ArrayListTest.class.getName(),
+                TreeMapTest.class.getName(),
+                TreeSetTest.class.getName(),
+                HashSetTest.class.getName(),
+                HashtableTest.class.getName(),
+                VectorTest.class.getName(),
+                LinkedListTest.class.getName(),
+                MathTest.class.getName(),
+        };
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java b/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java
new file mode 100644
index 0000000..6b740ba
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+import junit.framework.TestCase;
+
+
+@Suppress
+public class JniLibTest extends TestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        /*
+         * This causes the native shared library to be loaded when the
+         * class is first used.  The library is only loaded once, even if
+         * multiple classes include this line.
+         *
+         * The library must be in java.library.path, which is derived from
+         * LD_LIBRARY_PATH.  The actual library name searched for will be
+         * "libjni_lib_test.so" under Linux, but may be different on other
+         * platforms.
+         */
+        try {
+            System.loadLibrary("jni_lib_test");
+        } catch (UnsatisfiedLinkError ule) {
+            Log.e("JniLibTest", "WARNING: Could not load jni_lib_test natives");
+        }
+    }
+
+    private static native int nativeStaticThing(float f);
+    private native void nativeThing(int val);
+
+    public void testNativeCall() {
+        Log.i("JniLibTest", "JNI search path is "
+                + System.getProperty("java.library.path"));
+        Log.i("JniLibTest", "'jni_lib_test' becomes '"
+                + System.mapLibraryName("jni_lib_test") + "'");
+
+        int result = nativeStaticThing(1234.5f);
+        nativeThing(result);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LabelView.java b/tests/AndroidTests/src/com/android/unit_tests/LabelView.java
new file mode 100644
index 0000000..ac29776
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LabelView.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.view.View;
+
+/**
+ * Example of how to write a custom subclass of View. LabelView
+ * is used to draw simple text views. Note that it does not handle
+ * styled text or right-to-left writing systems.
+ *
+ */
+public class LabelView extends View {
+    /**
+     * Constructor.  This version is only needed if you will be instantiating
+     * the object manually (not from a layout XML file).
+     * @param context the application environment
+     */
+    public LabelView(Context context) {
+        super(context);
+        initLabelView();
+    }
+
+    /**
+     * Construct object, initializing with any attributes we understand from a
+     * layout file. These attributes are defined in
+     * SDK/assets/res/any/classes.xml.
+     * 
+     * @see android.view.View#View(android.content.Context, android.util.AttributeSet)
+    public LabelView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        initLabelView();
+
+        Resources.StyledAttributes a = context.obtainStyledAttributes(attrs,
+                R.styleable.LabelView);
+
+        CharSequence s = a.getString(R.styleable.LabelView_text);
+        if (s != null) {
+            setText(s.toString());
+        }
+
+        ColorStateList textColor = a.getColorList(R.styleable.
+                                                  LabelView_textColor);
+        if (textColor != null) {
+            setTextColor(textColor.getDefaultColor(0));
+        }
+
+        int textSize = a.getInt(R.styleable.LabelView_textSize, 0);
+        if (textSize > 0) {
+            setTextSize(textSize);
+        }
+
+        a.recycle();
+    }
+
+     */
+    private void initLabelView() {
+        mTextPaint = new Paint();
+        mTextPaint.setAntiAlias(true);
+        mTextPaint.setTextSize(16);
+        mTextPaint.setColor(0xFF000000);
+
+        mPaddingLeft = 3;
+        mPaddingTop = 3;
+        mPaddingRight = 3;
+        mPaddingBottom = 3;
+    }
+
+    /**
+     * Sets the text to display in this label
+     * @param text The text to display. This will be drawn as one line.
+     */
+    public void setText(String text) {
+        mText = text;
+        requestLayout();
+        invalidate();
+    }
+
+    /**
+     * Sets the text size for this label
+     * @param size Font size
+     */
+    public void setTextSize(int size) {
+        mTextPaint.setTextSize(size);
+        requestLayout();
+        invalidate();
+    }
+
+    /**
+     * Sets the text color for this label
+     * @param color ARGB value for the text
+     */
+    public void setTextColor(int color) {
+        mTextPaint.setColor(color);
+        invalidate();
+    }
+
+
+    /**
+     * @see android.view.View#measure(int, int)
+     */
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        setMeasuredDimension(measureWidth(widthMeasureSpec),
+                measureHeight(heightMeasureSpec));
+    }
+
+    /**
+     * Determines the width of this view
+     * @param measureSpec A measureSpec packed into an int
+     * @return The width of the view, honoring constraints from measureSpec
+     */
+    private int measureWidth(int measureSpec) {
+        int result;
+        int specMode = MeasureSpec.getMode(measureSpec);
+        int specSize = MeasureSpec.getSize(measureSpec);
+
+        if (specMode == MeasureSpec.EXACTLY) {
+            // We were told how big to be
+            result = specSize;
+        } else {
+            // Measure the text
+            result = (int) mTextPaint.measureText(mText) + mPaddingLeft
+                    + mPaddingRight;
+            if (specMode == MeasureSpec.AT_MOST) {
+                // Respect AT_MOST value if that was what is called for by measureSpec
+                result = Math.min(result, specSize);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Determines the height of this view
+     * @param measureSpec A measureSpec packed into an int
+     * @return The height of the view, honoring constraints from measureSpec
+     */
+    private int measureHeight(int measureSpec) {
+        int result;
+        int specMode = MeasureSpec.getMode(measureSpec);
+        int specSize = MeasureSpec.getSize(measureSpec);
+
+        mAscent = (int) mTextPaint.ascent();
+        if (specMode == MeasureSpec.EXACTLY) {
+            // We were told how big to be
+            result = specSize;
+        } else {
+            // Measure the text (beware: ascent is a negative number)
+            result = (int) (-mAscent + mTextPaint.descent()) + mPaddingTop
+                    + mPaddingBottom;
+            if (specMode == MeasureSpec.AT_MOST) {
+                // Respect AT_MOST value if that was what is called for by measureSpec
+                result = Math.min(result, specSize);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Render the text
+     * 
+     * @see android.view.View#onDraw(android.graphics.Canvas)
+     */
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        canvas.drawText(mText, mPaddingLeft, mPaddingTop - mAscent, mTextPaint);
+    }
+
+    private Paint mTextPaint;
+    private String mText;
+    private int mAscent;
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java b/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java
new file mode 100644
index 0000000..ca470cd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * This class contains performance tests for methods in java.util.LinkedList
+ * 
+ */
+@SuppressWarnings("unchecked")
+public class LinkedListTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    LinkedList<Integer> mLinkedList;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mLinkedList = new LinkedList();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            mLinkedList.add(i);
+        }
+    }
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    public void testLinkedListAdd() {
+        LinkedList<Integer> list = new LinkedList();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            list.add(i);
+            list.add(i);
+            list.add(i);
+            list.add(i);
+            list.add(i);
+            list.add(i);
+            list.add(i);
+            list.add(i);
+            list.add(i);
+            list.add(i);
+        }
+    }
+
+    public void testLinkedListAdd1() {
+        LinkedList<Integer> list = new LinkedList();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            list.add(0, i);
+            list.add(0, i);
+            list.add(0, i);
+            list.add(0, i);
+            list.add(0, i);
+            list.add(0, i);
+            list.add(0, i);
+            list.add(0, i);
+            list.add(0, i);
+            list.add(0, i);
+        }
+    }
+
+    public void testLinkedListToArray() {
+        Object array;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            array = list.toArray();
+            array = list.toArray();
+            array = list.toArray();
+            array = list.toArray();
+            array = list.toArray();
+            array = list.toArray();
+            array = list.toArray();
+            array = list.toArray();
+            array = list.toArray();
+            array = list.toArray();
+        }
+    }
+
+    public void testLinkedListSize() {
+        LinkedList<Integer> list = mLinkedList;
+        int len;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            len = list.size();
+            len = list.size();
+            len = list.size();
+            len = list.size();
+            len = list.size();
+            len = list.size();
+            len = list.size();
+            len = list.size();
+            len = list.size();
+            len = list.size();
+        }
+    }
+
+    public void testLinkedListGet() {
+        int element;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            element = list.get(i);
+            element = list.get(i);
+            element = list.get(i);
+            element = list.get(i);
+            element = list.get(i);
+            element = list.get(i);
+            element = list.get(i);
+            element = list.get(i);
+            element = list.get(i);
+            element = list.get(i);
+        }
+    }
+
+    public void testLinkedListContains() {
+        boolean flag;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = list.contains(i);
+            flag = list.contains(i);
+            flag = list.contains(i);
+            flag = list.contains(i);
+            flag = list.contains(i);
+            flag = list.contains(i);
+            flag = list.contains(i);
+            flag = list.contains(i);
+            flag = list.contains(i);
+            flag = list.contains(i);
+        }
+    }
+
+    public void testLinkedListToArray1() {
+        Integer[] rArray = new Integer[100];
+        Integer[] array;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+            array = list.toArray(rArray);
+        }
+    }
+
+    public void testLinkedListSet() {
+        LinkedList<Integer> list = mLinkedList;
+        int value1 = 500, value2 = 0;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            list.set(value1, value2);
+            list.set(value1, value2);
+            list.set(value1, value2);
+            list.set(value1, value2);
+            list.set(value1, value2);
+            list.set(value1, value2);
+            list.set(value1, value2);
+            list.set(value1, value2);
+            list.set(value1, value2);
+            list.set(value1, value2);
+        }
+    }
+
+    public void testLinkedListIndexOf() {
+        int index;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+            index = list.indexOf(0);
+
+        }
+    }
+
+    public void testLinkedListLastIndexOf() {
+        int index;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+            index = list.lastIndexOf(0);
+        }
+    }
+
+    public void testLinkedListRemove() {
+        int index;
+        LinkedList<Integer> list = new LinkedList(mLinkedList);
+        for (int i = 10; i > 0; i--) {
+            index = list.remove();
+            index = list.remove();
+            index = list.remove();
+            index = list.remove();
+            index = list.remove();
+            index = list.remove();
+            index = list.remove();
+            index = list.remove();
+            index = list.remove();
+            index = list.remove();
+        }
+    }
+
+    public void testLinkedListRemove1() {
+        int index;
+        LinkedList<Integer> list = new LinkedList(mLinkedList);
+        for (int i = 10; i > 0; i--) {
+            index = list.remove(0);
+            index = list.remove(0);
+            index = list.remove(0);
+            index = list.remove(0);
+            index = list.remove(0);
+            index = list.remove(0);
+            index = list.remove(0);
+            index = list.remove(0);
+            index = list.remove(0);
+            index = list.remove(0);
+        }
+    }
+
+    public void testLinkedListRemoveFirst() {
+        int index;
+        LinkedList<Integer> list = new LinkedList(mLinkedList);
+        for (int i = 10; i > 0; i--) {
+            index = list.removeFirst();
+            index = list.removeFirst();
+            index = list.removeFirst();
+            index = list.removeFirst();
+            index = list.removeFirst();
+            index = list.removeFirst();
+            index = list.removeFirst();
+            index = list.removeFirst();
+            index = list.removeFirst();
+            index = list.removeFirst();
+        }
+    }
+
+    public void testLinkedListRemoveLast() {
+        int index;
+        LinkedList<Integer> list = new LinkedList(mLinkedList);
+        for (int i = 10; i > 0; i--) {
+            index = list.removeLast();
+            index = list.removeLast();
+            index = list.removeLast();
+            index = list.removeLast();
+            index = list.removeLast();
+            index = list.removeLast();
+            index = list.removeLast();
+            index = list.removeLast();
+            index = list.removeLast();
+            index = list.removeLast();
+        }
+    }
+
+    public void testLinkedListAddAll() {
+        LinkedList<Integer> mList = mLinkedList;
+        boolean flag;
+        LinkedList<Integer> list = new LinkedList();
+        for (int i = 10; i > 0; i--) {
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+            flag = list.addAll(mList);
+        }
+    }
+
+    public void testLinkedListRemove2() {
+        LinkedList<String> list;
+        String s = new String("a");
+        list = new LinkedList();
+        for (int j = 1000; j > 0; j--) {
+            list.add("a");
+            list.add("b");
+        }
+        boolean flag;
+        for (int i = 10; i > 0; i--) {
+            flag = list.remove(s);
+            flag = list.remove(s);
+            flag = list.remove(s);
+            flag = list.remove(s);
+            flag = list.remove(s);
+            flag = list.remove(s);
+            flag = list.remove(s);
+            flag = list.remove(s);
+            flag = list.remove(s);
+            flag = list.remove(s);
+        }
+    }
+
+    public void testLinkedListAddAll1() {
+        LinkedList<Integer> mList = new LinkedList();
+        int pos = 0;
+        boolean flag;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = 0; i < 10; i++) {
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+            flag = mList.addAll(pos, list);
+        }
+    }
+
+    public void testLinkedListClone() {
+        Object rObj;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = 100; i > 0; i--) {
+            rObj = list.clone();
+            rObj = list.clone();
+            rObj = list.clone();
+            rObj = list.clone();
+            rObj = list.clone();
+            rObj = list.clone();
+            rObj = list.clone();
+            rObj = list.clone();
+            rObj = list.clone();
+            rObj = list.clone();
+        }
+    }
+
+    public void testLinkedListHashcode() {
+        int element;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            element = list.hashCode();
+            element = list.hashCode();
+            element = list.hashCode();
+            element = list.hashCode();
+            element = list.hashCode();
+            element = list.hashCode();
+            element = list.hashCode();
+            element = list.hashCode();
+            element = list.hashCode();
+            element = list.hashCode();
+        }
+    }
+
+    public void testLinkedListElement() {
+        int element;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            element = list.element();
+            element = list.element();
+            element = list.element();
+            element = list.element();
+            element = list.element();
+            element = list.element();
+            element = list.element();
+            element = list.element();
+            element = list.element();
+            element = list.element();
+        }
+    }
+
+    public void testLinkedListToString() {
+        String str;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            str = list.toString();
+            str = list.toString();
+            str = list.toString();
+            str = list.toString();
+            str = list.toString();
+            str = list.toString();
+            str = list.toString();
+            str = list.toString();
+            str = list.toString();
+            str = list.toString();
+        }
+    }
+
+    public void testLinkedListIsEmpty() {
+        boolean flag;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+            flag = list.isEmpty();
+        }
+    }
+
+    public void testLinkedListOffer() {
+        LinkedList<Integer> list = new LinkedList();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            list.offer(i);
+            list.offer(i);
+            list.offer(i);
+            list.offer(i);
+            list.offer(i);
+            list.offer(i);
+            list.offer(i);
+            list.offer(i);
+            list.offer(i);
+            list.offer(i);
+        }
+    }
+
+    public void testLinkedListPeek() {
+        int element;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            element = list.peek();
+            element = list.peek();
+            element = list.peek();
+            element = list.peek();
+            element = list.peek();
+            element = list.peek();
+            element = list.peek();
+            element = list.peek();
+            element = list.peek();
+            element = list.peek();
+        }
+    }
+
+    public void testLinkedListPoll() {
+        int element;
+        LinkedList<Integer> list = new LinkedList(mLinkedList);
+        for (int i = 10; i > 0; i--) {
+            element = list.poll();
+            element = list.poll();
+            element = list.poll();
+            element = list.poll();
+            element = list.poll();
+            element = list.poll();
+            element = list.poll();
+            element = list.poll();
+            element = list.poll();
+            element = list.poll();
+        }
+    }
+
+    public void testLinkedListAddLast() {
+        LinkedList<Integer> list = new LinkedList();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            list.addLast(i);
+            list.addLast(i);
+            list.addLast(i);
+            list.addLast(i);
+            list.addLast(i);
+            list.addLast(i);
+            list.addLast(i);
+            list.addLast(i);
+            list.addLast(i);
+            list.addLast(i);
+        }
+    }
+
+    public void testLinkedListAddFirst() {
+        LinkedList<Integer> list = new LinkedList();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            list.addFirst(i);
+            list.addFirst(i);
+            list.addFirst(i);
+            list.addFirst(i);
+            list.addFirst(i);
+            list.addFirst(i);
+            list.addFirst(i);
+            list.addFirst(i);
+            list.addFirst(i);
+            list.addFirst(i);
+        }
+    }
+
+    public void testLinkedListIterator() {
+        ListIterator iterator;
+        LinkedList<Integer> list = mLinkedList;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+            iterator = list.listIterator();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java b/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java
new file mode 100644
index 0000000..83e0758
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.*;
+import android.text.method.*;
+import android.text.style.*;
+import android.text.util.*;
+import android.widget.*;
+
+/**
+ * LinkifyTest tests {@link Linkify}.
+ */
+public class LinkifyTest extends AndroidTestCase {
+
+    @SmallTest
+    public void testNothing() throws Exception {
+        TextView tv;
+
+        tv = new TextView(getContext());
+        tv.setText("Hey, foo@google.com, call 415-555-1212.");
+
+        assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod);
+        assertTrue(tv.getUrls().length == 0);
+    }
+
+    @MediumTest
+    public void testNormal() throws Exception {
+        TextView tv;
+
+        tv = new TextView(getContext());
+        tv.setAutoLinkMask(Linkify.ALL);
+        tv.setText("Hey, foo@google.com, call 415-555-1212.");
+
+        assertTrue(tv.getMovementMethod() instanceof LinkMovementMethod);
+        assertTrue(tv.getUrls().length == 2);
+    }
+
+    @SmallTest
+    public void testUnclickable() throws Exception {
+        TextView tv;
+
+        tv = new TextView(getContext());
+        tv.setAutoLinkMask(Linkify.ALL);
+        tv.setLinksClickable(false);
+        tv.setText("Hey, foo@google.com, call 415-555-1212.");
+
+        assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod);
+        assertTrue(tv.getUrls().length == 2);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java b/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java
new file mode 100644
index 0000000..0b8ec74
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.net.Credentials;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+public class LocalSocketTest extends TestCase {
+
+    @SmallTest
+    public void testBasic() throws Exception {
+        LocalServerSocket ss;
+        LocalSocket ls;
+        LocalSocket ls1;
+
+        ss = new LocalServerSocket("com.android.unit_tests.LocalSocketTest");
+
+        ls = new LocalSocket();
+
+        ls.connect(new LocalSocketAddress("com.android.unit_tests.LocalSocketTest"));
+
+        ls1 = ss.accept();
+
+        // Test trivial read and write
+        ls.getOutputStream().write(42);
+
+        assertEquals(42, ls1.getInputStream().read());
+
+        // Test getting credentials
+        Credentials c = ls1.getPeerCredentials();
+
+        MoreAsserts.assertNotEqual(0, c.getPid());
+
+        // Test sending and receiving file descriptors
+        ls.setFileDescriptorsForSend(
+                new FileDescriptor[]{FileDescriptor.in});
+
+        ls.getOutputStream().write(42);
+
+        assertEquals(42, ls1.getInputStream().read());
+
+        FileDescriptor[] out = ls1.getAncillaryFileDescriptors();
+
+        assertEquals(1, out.length);
+
+        // Test multible byte write and available()
+        ls1.getOutputStream().write(new byte[]{0, 1, 2, 3, 4, 5}, 1, 5);
+
+        assertEquals(1, ls.getInputStream().read());
+        assertEquals(4, ls.getInputStream().available());
+
+        byte[] buffer = new byte[16];
+        int countRead;
+
+        countRead = ls.getInputStream().read(buffer, 1, 15);
+
+        assertEquals(4, countRead);
+        assertEquals(2, buffer[1]);
+        assertEquals(3, buffer[2]);
+        assertEquals(4, buffer[3]);
+        assertEquals(5, buffer[4]);
+
+        // Try various array-out-of-bound cases
+        try {
+            ls.getInputStream().read(buffer, 1, 16);
+            fail("expected exception");
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // excpected
+        }
+
+        try {
+            ls.getOutputStream().write(buffer, 1, 16);
+            fail("expected exception");
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // excpected
+        }
+
+        try {
+            ls.getOutputStream().write(buffer, -1, 15);
+            fail("expected exception");
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // excpected
+        }
+
+        try {
+            ls.getOutputStream().write(buffer, 0, -1);
+            fail("expected exception");
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // excpected
+        }
+
+        try {
+            ls.getInputStream().read(buffer, -1, 15);
+            fail("expected exception");
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // excpected
+        }
+
+        try {
+            ls.getInputStream().read(buffer, 0, -1);
+            fail("expected exception");
+        } catch (ArrayIndexOutOfBoundsException ex) {
+            // excpected
+        }
+
+        // Try read of length 0
+        ls.getOutputStream().write(42);
+        countRead = ls1.getInputStream().read(buffer, 0, 0);
+        assertEquals(0, countRead);
+        assertEquals(42, ls1.getInputStream().read());
+
+        ss.close();
+
+        ls.close();
+
+        // Try write on closed socket
+
+        try {
+            ls.getOutputStream().write(42);
+            fail("expected exception");
+        } catch (IOException ex) {
+            // Expected
+        }
+
+        // Try read on closed socket
+
+        try {
+            ls.getInputStream().read();
+            fail("expected exception");
+        } catch (IOException ex) {
+            // Expected
+        }
+
+        // Try write on socket whose peer has closed
+
+        try {
+            ls1.getOutputStream().write(42);
+            fail("expected exception");
+        } catch (IOException ex) {
+            // Expected
+        }
+
+        // Try read on socket whose peer has closed
+
+        assertEquals(-1, ls1.getInputStream().read());
+
+        ls1.close();
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java
new file mode 100644
index 0000000..47c7522
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.Context;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+@Suppress
+public class LocationManagerTest extends AndroidTestCase {
+    private static final String LOG_TAG = "LocationManagerTest";
+
+    private LocationManager manager;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        manager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+        assertNotNull(manager);
+    }
+
+    public void testGetBogusProvider() {
+        LocationProvider p = manager.getProvider("bogus");
+        assertNull(p);
+    }
+
+    public void testGetNetworkProvider() {
+        LocationProvider p = manager.getProvider("network");
+        assertNotNull(p);
+    }
+
+    public void testGetGpsProvider() {
+        LocationProvider p = manager.getProvider("gps");
+        assertNotNull(p);
+    }
+
+    public void testGetBestProviderEmptyCriteria() {
+        String p = manager.getBestProvider(new Criteria(), true);
+        assertNotNull(p);
+    }
+
+    public void testGetBestProviderPowerCriteria() {
+        Criteria c = new Criteria();
+        c.setPowerRequirement(Criteria.POWER_HIGH);
+        String p = manager.getBestProvider(c, true);
+        assertNotNull(p);
+
+        c.setPowerRequirement(Criteria.POWER_MEDIUM);
+        p = manager.getBestProvider(c, true);
+        assertNotNull(p);
+
+        c.setPowerRequirement(Criteria.POWER_LOW);
+        p = manager.getBestProvider(c, true);
+        assertNotNull(p);
+
+        c.setPowerRequirement(Criteria.NO_REQUIREMENT);
+        p = manager.getBestProvider(c, true);
+        assertNotNull(p);
+    }
+
+    public void testGpsTracklog() {
+        LocationProvider p = manager.getProvider("gps");
+        assertNotNull(p);
+
+        // TODO: test requestUpdates method
+    }
+
+    public void testLocationConversions() {
+        String loc1 = Location.convert(-80.075, Location.FORMAT_DEGREES);
+        Log.i(LOG_TAG, "Input = " + (-80.075) + ", output = " + loc1);
+        assertEquals("-80.075", loc1);
+
+        String loc1b = Location.convert(-80.0, Location.FORMAT_DEGREES);
+        Log.i(LOG_TAG, "Input = " + (-80.0) + ", output = " + loc1b);
+        assertEquals("-80", loc1b);
+
+        String loc2 = Location.convert(-80.085, Location.FORMAT_DEGREES);
+        Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc2);
+        assertEquals("-80.085", loc2);
+
+        String loc3 = Location.convert(-80.085, Location.FORMAT_MINUTES);
+        Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc3);
+        assertEquals("-80:5.1", loc3);
+
+        String loc4 = Location.convert(-80.085, Location.FORMAT_SECONDS);
+        Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc4);
+        assertEquals("-80:5:6", loc4);
+
+        String loc5 = Location.convert(5 + 0.5f / 60.0f, Location.FORMAT_MINUTES);
+        Log.i(LOG_TAG, "Input = 5:0.5, output = " + loc5);
+        int index = loc5.indexOf(':');
+        String loc5a = loc5.substring(0, index);
+        Log.i(LOG_TAG, "loc5a = " + loc5a);
+        assertTrue(loc5a.equals("5"));
+        String loc5b = loc5.substring(index + 1);
+        Log.i(LOG_TAG, "loc5b = " + loc5b);
+        double minutes = Double.parseDouble(loc5b);
+        Log.i(LOG_TAG, "minutes = " + minutes);
+        assertTrue(Math.abs(minutes - 0.5) < 0.0001);
+
+        String loc6 = Location.convert(0.1, Location.FORMAT_DEGREES);
+        Log.i(LOG_TAG, "loc6 = " + loc6);
+        assertEquals(loc6, "0.1");
+
+        String loc7 = Location.convert(0.1, Location.FORMAT_MINUTES);
+        Log.i(LOG_TAG, "loc7 = " + loc7);
+        assertEquals(loc7, "0:6");
+
+        String loc8 = Location.convert(0.1, Location.FORMAT_SECONDS);
+        Log.i(LOG_TAG, "loc8 = " + loc8);
+        assertEquals(loc8, "0:6:0");
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LogTest.java b/tests/AndroidTests/src/com/android/unit_tests/LogTest.java
new file mode 100644
index 0000000..786c4b9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LogTest.java
@@ -0,0 +1,152 @@
+package com.android.unit_tests;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import android.os.SystemProperties;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+//This is an empty TestCase.
+@Suppress
+public class LogTest extends TestCase {
+    private static final String PROPERTY_TAG = "log.tag.LogTest";
+    private static final String LOG_TAG = "LogTest";
+
+
+    // TODO: remove this test once we uncomment out the following test.
+    public void testLogTestDummy() {
+      return;
+    }
+
+
+    /* TODO: This test is commented out because we will not be able to set properities. Fix the test.
+    public void testIsLoggable() {
+        // First clear any SystemProperty setting for our test key.
+        SystemProperties.set(PROPERTY_TAG, null);
+        
+        String value = SystemProperties.get(PROPERTY_TAG);
+        Assert.assertTrue(value == null || value.length() == 0);
+        
+        // Check to make sure that all levels expect for INFO, WARN, ERROR, and ASSERT are loggable. 
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+        
+        // Set the log level to be VERBOSE for this tag.
+        SystemProperties.set(PROPERTY_TAG, "VERBOSE");
+        
+        // Test to make sure all log levels >= VERBOSE are loggable.
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.DEBUG));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+        
+        // Set the log level to be DEBUG for this tag.
+        SystemProperties.set(PROPERTY_TAG, "DEBUG");
+        
+        // Test to make sure all log levels >= DEBUG are loggable.
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.DEBUG));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+        
+        // Set the log level to be INFO for this tag.
+        SystemProperties.set(PROPERTY_TAG, "INFO");
+        
+        // Test to make sure all log levels >= INFO are loggable.
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+        
+        // Set the log level to be WARN for this tag.
+        SystemProperties.set(PROPERTY_TAG, "WARN");
+        
+        // Test to make sure all log levels >= WARN are loggable.
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+        
+        // Set the log level to be ERROR for this tag.
+        SystemProperties.set(PROPERTY_TAG, "ERROR");
+        
+        // Test to make sure all log levels >= ERROR are loggable.
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+        
+        // Set the log level to be ASSERT for this tag.
+        SystemProperties.set(PROPERTY_TAG, "ASSERT");
+        
+        // Test to make sure all log levels >= ASSERT are loggable.
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR));
+        Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+        
+        // Set the log level to be SUPPRESS for this tag.
+        SystemProperties.set(PROPERTY_TAG, "SUPPRESS");
+        
+        // Test to make sure all log levels >= ASSERT are loggable.
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR));
+        Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ASSERT));
+    }
+    */
+    
+    public static class PerformanceTest extends TestCase implements PerformanceTestCase {
+        private static final int ITERATIONS = 1000;
+
+        @Override
+        public void setUp() {
+            SystemProperties.set(LOG_TAG, "VERBOSE");
+        }
+        
+        public boolean isPerformanceOnly() {
+            return true;
+        }
+        
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testIsLoggable() {
+            boolean canLog = false;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+                canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+            }
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MathTest.java b/tests/AndroidTests/src/com/android/unit_tests/MathTest.java
new file mode 100644
index 0000000..caf2d20
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/MathTest.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+/**
+ * 
+ * Implements basic performance test functionality for java.lang.Math
+ * 
+ */
+
+public class MathTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    public static final double sDouble1 = -2450.50;
+    public static final double sDouble2 = -500;
+    public static final float sFloat = 300.50f;
+    public static final int sInt = 90;
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    public void testDoubleAbs() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+            result = Math.abs(sDouble1);
+        }
+    }
+
+    public void testFloatAbs() {
+        float result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+            result = Math.abs(sFloat);
+        }
+    }
+
+    public void testMathSin() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+            result = Math.sin(sDouble1);
+        }
+    }
+
+    public void testMathCos() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+            result = Math.cos(sDouble1);
+        }
+    }
+
+    public void testMathTan() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+            result = Math.tan(sDouble1);
+        }
+    }
+
+    public void testMathASin() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+            result = Math.asin(sDouble1);
+        }
+    }
+
+    public void testMathACos() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+            result = Math.acos(sDouble1);
+        }
+    }
+
+    public void testMathATan() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+            result = Math.atan(sDouble1);
+        }
+    }
+
+    public void testMathLog() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+            result = Math.log(sDouble1);
+        }
+    }
+
+    public void testMathSqrt() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+            result = Math.sqrt(sDouble1);
+        }
+    }
+
+    public void testMathCeil() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+            result = Math.ceil(sDouble1);
+        }
+    }
+
+    public void testMathRound() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+            result = Math.round(sDouble1);
+        }
+    }
+
+    public void testMathFloor() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+            result = Math.floor(sDouble1);
+        }
+    }
+
+    public void testMathExp() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+            result = Math.exp(sDouble1);
+        }
+    }
+
+    /**
+     * 
+     */
+
+    public void testMathPow() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+            result = Math.pow(sDouble1, sDouble2);
+        }
+    }
+
+    public void testMathMax() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+            result = Math.max(sDouble1, sDouble2);
+        }
+    }
+
+    public void testMathMin() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+            result = Math.min(sDouble1, sDouble2);
+        }
+    }
+
+    public void testMathRandom() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.random();
+            result = Math.random();
+            result = Math.random();
+            result = Math.random();
+            result = Math.random();
+            result = Math.random();
+            result = Math.random();
+            result = Math.random();
+            result = Math.random();
+            result = Math.random();
+        }
+    }
+
+    public void testMathIEEERemainder() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+            result = Math.IEEEremainder(sDouble1, sDouble2);
+        }
+    }
+
+    public void testMathToDegrees() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+            result = Math.toDegrees(sDouble1);
+        }
+    }
+
+    public void testMathToRadians() {
+        double result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+            result = Math.toRadians(sDouble1);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
new file mode 100644
index 0000000..c436726
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.android.internal.view.menu.MenuBuilder;
+
+import junit.framework.Assert;
+
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+public class MenuTest extends AndroidTestCase {
+
+    private MenuBuilder mMenu;
+
+    public void setUp() throws Exception {
+        super.setUp();
+        mMenu = new MenuBuilder(super.getContext());
+    }
+
+    @SmallTest
+    public void testItemId() {
+        final int id = 512;
+        final MenuItem item = mMenu.add(0, id, 0, "test");
+        
+        Assert.assertEquals(id, item.getItemId());
+        Assert.assertEquals(item, mMenu.findItem(id));
+        Assert.assertEquals(0, mMenu.findItemIndex(id));
+    }
+    
+    @SmallTest
+    public void testGroupId() {
+        final int groupId = 541;
+        final int item1Index = 1;
+        final int item2Index = 3;
+        
+        mMenu.add(0, 0, item1Index - 1, "ignore");
+        final MenuItem item = mMenu.add(groupId, 0, item1Index, "test");
+        mMenu.add(0, 0, item2Index - 1, "ignore");
+        final MenuItem item2 = mMenu.add(groupId, 0, item2Index, "test2");
+        
+        Assert.assertEquals(groupId, item.getGroupId());
+        Assert.assertEquals(groupId, item2.getGroupId());
+        Assert.assertEquals(item1Index, mMenu.findGroupIndex(groupId));
+        Assert.assertEquals(item2Index, mMenu.findGroupIndex(groupId, item1Index + 1));
+    }
+    
+    @SmallTest
+    public void testGroup() {
+        // This test does the following
+        //  1. Create a grouped item in the menu
+        //  2. Check that findGroupIndex() finds the grouped item.
+        //  3. Check that findGroupIndex() doesn't find a non-existent group.
+
+        final int GROUP_ONE = Menu.FIRST;
+        final int GROUP_TWO = Menu.FIRST + 1;
+
+        mMenu.add(GROUP_ONE, 0, 0, "Menu text");
+        Assert.assertEquals(mMenu.findGroupIndex(GROUP_ONE), 0);
+        Assert.assertEquals(mMenu.findGroupIndex(GROUP_TWO), -1);
+        //TODO: expand this test case to do multiple groups,
+        //adding and removing, hiding and showing, etc.
+    }
+
+    @SmallTest
+    public void testIsShortcutWithAlpha() throws Exception {
+        mMenu.setQwertyMode(true);
+        mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+        Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+                                              makeKeyEvent(KeyEvent.KEYCODE_A,  0)));
+        Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_B,
+                                               makeKeyEvent(KeyEvent.KEYCODE_B,  0)));
+    }
+
+    @SmallTest
+    public void testIsShortcutWithNumeric() throws Exception {
+        mMenu.setQwertyMode(false);
+        mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+        Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_2,
+                                              makeKeyEvent(KeyEvent.KEYCODE_2,  0)));
+        Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+                                               makeKeyEvent(KeyEvent.KEYCODE_A,  0)));
+    }
+
+    @SmallTest
+    public void testIsShortcutWithAlt() throws Exception {
+        mMenu.setQwertyMode(true);
+        mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+        Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+                                              makeKeyEvent(KeyEvent.KEYCODE_A,
+                                                           KeyEvent.META_ALT_ON)));
+        Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+                                              makeKeyEvent(KeyEvent.KEYCODE_A,
+                                                           KeyEvent.META_SYM_ON)));
+    }
+
+    @SmallTest
+    public void testIsNotShortcutWithShift() throws Exception {
+        mMenu.setQwertyMode(true);
+        mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+        Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+                                              makeKeyEvent(KeyEvent.KEYCODE_A,
+                                                           KeyEvent.META_SHIFT_ON)));
+    }
+
+    @SmallTest
+    public void testIsNotShortcutWithSym() throws Exception {
+        mMenu.setQwertyMode(true);
+        mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+        Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+                                              makeKeyEvent(KeyEvent.KEYCODE_A,
+                                                           KeyEvent.META_SYM_ON)));
+    }
+    
+    @SmallTest
+    public void testIsShortcutWithUpperCaseAlpha() throws Exception {
+        mMenu.setQwertyMode(true);
+        mMenu.add(0, 0, 0, "test").setShortcut('2', 'A');
+        Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+                                              makeKeyEvent(KeyEvent.KEYCODE_A,  0)));
+    }
+
+    @SmallTest
+    public void testIsShortcutWithBackspace() throws Exception {
+        mMenu.setQwertyMode(true);
+        mMenu.add(0, 0, 0, "test").setShortcut('2', '\b');
+        Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_DEL,
+                                              makeKeyEvent(KeyEvent.KEYCODE_DEL,  0)));
+    }
+
+    @SmallTest
+    public void testIsShortcutWithNewline() throws Exception {
+        mMenu.setQwertyMode(true);
+        mMenu.add(0, 0, 0, "test").setShortcut('2', '\n');
+        Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_ENTER,
+                                              makeKeyEvent(KeyEvent.KEYCODE_ENTER,  0)));
+    }
+    
+    @SmallTest
+    public void testOrder() {
+        final String a = "a", b = "b", c = "c";
+        final int firstOrder = 7, midOrder = 8, lastOrder = 9;
+        
+        mMenu.add(0, 0, lastOrder, c);
+        mMenu.add(0, 0, firstOrder, a);
+        mMenu.add(0, 0, midOrder, b);
+        
+        Assert.assertEquals(firstOrder, mMenu.getItem(0).getOrder());
+        Assert.assertEquals(a, mMenu.getItem(0).getTitle());
+        Assert.assertEquals(midOrder, mMenu.getItem(1).getOrder());
+        Assert.assertEquals(b, mMenu.getItem(1).getTitle());
+        Assert.assertEquals(lastOrder, mMenu.getItem(2).getOrder());
+        Assert.assertEquals(c, mMenu.getItem(2).getTitle());
+    }
+
+    @SmallTest
+    public void testTitle() {
+        final String title = "test";
+        final MenuItem stringItem = mMenu.add(title);
+        final MenuItem resItem = mMenu.add(R.string.menu_test);
+        
+        Assert.assertEquals(title, stringItem.getTitle());
+        Assert.assertEquals(getContext().getResources().getString(R.string.menu_test), resItem
+                .getTitle());
+    }
+
+    @SmallTest
+    public void testCheckable() {
+        final int groupId = 1;
+        final MenuItem item1 = mMenu.add(groupId, 1, 0, "item1");
+        final MenuItem item2 = mMenu.add(groupId, 2, 0, "item2");
+        
+        // Set to exclusive
+        mMenu.setGroupCheckable(groupId, true, true);
+        Assert.assertTrue("Item was not set to checkable", item1.isCheckable());
+        item1.setChecked(true);
+        Assert.assertTrue("Item did not get checked", item1.isChecked());
+        Assert.assertFalse("Item was not unchecked due to exclusive checkable", item2.isChecked());
+        mMenu.findItem(2).setChecked(true);
+        Assert.assertTrue("Item did not get checked", item2.isChecked());
+        Assert.assertFalse("Item was not unchecked due to exclusive checkable", item1.isChecked());
+        
+        // Multiple non-exlusive checkable items
+        mMenu.setGroupCheckable(groupId, true, false);
+        Assert.assertTrue("Item was not set to checkable", item1.isCheckable());
+        item1.setChecked(false);
+        Assert.assertFalse("Item did not get unchecked", item1.isChecked());
+        item1.setChecked(true);
+        Assert.assertTrue("Item did not get checked", item1.isChecked());
+        mMenu.findItem(2).setChecked(true);
+        Assert.assertTrue("Item did not get checked", item2.isChecked());
+        Assert.assertTrue("Item was unchecked when it shouldnt have been", item1.isChecked());
+    }
+    
+    @SmallTest
+    public void testVisibility() {
+        final MenuItem item1 = mMenu.add(0, 1, 0, "item1");
+        final MenuItem item2 = mMenu.add(0, 2, 0, "item2");
+        
+        // Should start as visible
+        Assert.assertTrue("Item did not start as visible", item1.isVisible());
+        Assert.assertTrue("Item did not start as visible", item2.isVisible());
+
+        // Hide
+        item1.setVisible(false);
+        Assert.assertFalse("Item did not become invisible", item1.isVisible());
+        mMenu.findItem(2).setVisible(false);
+        Assert.assertFalse("Item did not become invisible", item2.isVisible());
+    }
+    
+    @SmallTest
+    public void testSubMenu() {
+        final SubMenu subMenu = mMenu.addSubMenu(0, 0, 0, "submenu");
+        final MenuItem subMenuItem = subMenu.getItem();
+        final MenuItem item1 = subMenu.add(0, 1, 0, "item1");
+        final MenuItem item2 = subMenu.add(0, 2, 0, "item2");
+        
+        // findItem should recurse into submenus
+        Assert.assertEquals(item1, mMenu.findItem(1));
+        Assert.assertEquals(item2, mMenu.findItem(2));
+    }
+    
+    @SmallTest
+    public void testRemove() {
+        final int groupId = 1;
+        final MenuItem item1 = mMenu.add(groupId, 1, 0, "item1");
+        final MenuItem item2 = mMenu.add(groupId, 2, 0, "item2");
+        final MenuItem item3 = mMenu.add(groupId, 3, 0, "item3");
+        final MenuItem item4 = mMenu.add(groupId, 4, 0, "item4");
+        final MenuItem item5 = mMenu.add(groupId, 5, 0, "item5");
+        final MenuItem item6 = mMenu.add(0, 6, 0, "item6");
+        
+        Assert.assertEquals(item1, mMenu.findItem(1));
+        mMenu.removeItemAt(0);
+        Assert.assertNull(mMenu.findItem(1));
+        
+        Assert.assertEquals(item2, mMenu.findItem(2));
+        mMenu.removeItem(2);
+        Assert.assertNull(mMenu.findItem(2));
+        
+        Assert.assertEquals(item3, mMenu.findItem(3));
+        Assert.assertEquals(item4, mMenu.findItem(4));
+        Assert.assertEquals(item5, mMenu.findItem(5));
+        mMenu.removeGroup(groupId);
+        Assert.assertNull(mMenu.findItem(3));
+        Assert.assertNull(mMenu.findItem(4));
+        Assert.assertNull(mMenu.findItem(5));
+        
+        Assert.assertEquals(item6, mMenu.findItem(6));
+        mMenu.clear();
+        Assert.assertNull(mMenu.findItem(6));
+    }
+    
+    private KeyEvent makeKeyEvent(int keyCode, int metaState) {
+        return new KeyEvent(0L, 0L, KeyEvent.ACTION_DOWN, keyCode, 0, metaState);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java b/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java
new file mode 100644
index 0000000..2f3df10
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class MonitorTest extends TestCase {
+
+    @MediumTest
+    public void testWaitArgumentsTest() throws Exception {
+            /* Try some valid arguments.  These should all
+             * return very quickly.
+             */
+            try {
+                synchronized (this) {
+                    /* millisecond version */
+                    wait(1);
+                    wait(10);
+
+                    /* millisecond + nanosecond version */
+                    wait(0, 1);
+                    wait(0, 999999);
+                    wait(1, 1);
+                    wait(1, 999999);
+                }
+            } catch (InterruptedException ex) {
+                throw new RuntimeException("good Object.wait() interrupted",
+                        ex);
+            } catch (Exception ex) {
+                throw new RuntimeException("Unexpected exception when calling" +
+                        "Object.wait() with good arguments", ex);
+            }
+
+            /* Try some invalid arguments.
+             */
+            boolean sawException = false;
+            try {
+                synchronized (this) {
+                    wait(-1);
+                }
+            } catch (InterruptedException ex) {
+                throw new RuntimeException("bad Object.wait() interrupted", ex);
+            } catch (IllegalArgumentException ex) {
+                sawException = true;
+            } catch (Exception ex) {
+                throw new RuntimeException("Unexpected exception when calling" +
+                        "Object.wait() with bad arguments", ex);
+            }
+            if (!sawException) {
+                throw new RuntimeException("bad call to Object.wait() should " +
+                        "have thrown IllegalArgumentException");
+            }
+
+            sawException = false;
+            try {
+                synchronized (this) {
+                    wait(0, -1);
+                }
+            } catch (InterruptedException ex) {
+                throw new RuntimeException("bad Object.wait() interrupted", ex);
+            } catch (IllegalArgumentException ex) {
+                sawException = true;
+            } catch (Exception ex) {
+                throw new RuntimeException("Unexpected exception when calling" +
+                        "Object.wait() with bad arguments", ex);
+            }
+            if (!sawException) {
+                throw new RuntimeException("bad call to Object.wait() should " +
+                        "have thrown IllegalArgumentException");
+            }
+
+            sawException = false;
+            try {
+                synchronized (this) {
+                    /* The legal range of nanos is 0-999999. */
+                    wait(0, 1000000);
+                }
+            } catch (InterruptedException ex) {
+                throw new RuntimeException("bad Object.wait() interrupted", ex);
+            } catch (IllegalArgumentException ex) {
+                sawException = true;
+            } catch (Exception ex) {
+                throw new RuntimeException("Unexpected exception when calling" +
+                        "Object.wait() with bad arguments", ex);
+            }
+            if (!sawException) {
+                throw new RuntimeException("bad call to Object.wait() should " +
+                        "have thrown IllegalArgumentException");
+            }
+    }
+
+    private class Interrupter extends Thread {
+            Waiter waiter;
+
+            Interrupter(String name, Waiter waiter) {
+                super(name);
+                this.waiter = waiter;
+            }
+
+            public void run() {
+                try {
+                    run_inner();
+                } catch (Throwable t) {
+                    MonitorTest.errorException = t;
+                    MonitorTest.testThread.interrupt();
+                }
+            }
+
+            void run_inner() {
+                waiter.spin = true;
+                // System.out.println("InterruptTest: starting waiter");
+                waiter.start();
+
+                try {
+                    Thread.currentThread().sleep(500);
+                } catch (InterruptedException ex) {
+                    throw new RuntimeException("Test sleep interrupted.", ex);
+                }
+
+                /* Waiter is spinning, and its monitor should still be thin.
+                 */
+                // System.out.println("Test interrupting waiter");
+                waiter.interrupt();
+                waiter.spin = false;
+
+                for (int i = 0; i < 3; i++) {
+                    /* Wait for the waiter to start waiting.
+                     */
+                    synchronized (waiter.interrupterLock) {
+                        try {
+                            waiter.interrupterLock.wait();
+                        } catch (InterruptedException ex) {
+                            throw new RuntimeException("Test wait interrupted.", ex);
+                        }
+                    }
+
+                    /* Before interrupting, grab the waiter lock, which
+                     * guarantees that the waiter is already sitting in wait().
+                     */
+                    synchronized (waiter) {
+                        //System.out.println("Test interrupting waiter (" + i + ")");
+                        waiter.interrupt();
+                    }
+                }
+
+                // System.out.println("Test waiting for waiter to die.");
+                try {
+                    waiter.join();
+                } catch (InterruptedException ex) {
+                    throw new RuntimeException("Test join interrupted.", ex);
+                }
+                // System.out.println("InterruptTest done.");
+            }
+        }
+
+    private class Waiter extends Thread {
+            Object interrupterLock = new Object();
+            Boolean spin = false;
+
+            Waiter(String name) {
+                super(name);
+            }
+
+            public void run() {
+                try {
+                    run_inner();
+                } catch (Throwable t) {
+                    MonitorTest.errorException = t;
+                    MonitorTest.testThread.interrupt();
+                }
+            }
+
+            void run_inner() {
+                // System.out.println("Waiter spinning");
+                while (spin) {
+                    // We're going to get interrupted while we spin.
+                }
+                if (interrupted()) {
+                    // System.out.println("Waiter done spinning; interrupted.");
+                } else {
+                    throw new RuntimeException("Thread not interrupted " +
+                                               "during spin");
+                }
+
+                synchronized (this) {
+                    Boolean sawEx = false;
+
+                    try {
+                        synchronized (interrupterLock) {
+                            interrupterLock.notify();
+                        }
+                        // System.out.println("Waiter calling wait()");
+                        this.wait();
+                    } catch (InterruptedException ex) {
+                        sawEx = true;
+                        // System.out.println("wait(): Waiter caught " + ex);
+                    }
+                    // System.out.println("wait() finished");
+
+                    if (!sawEx) {
+                        throw new RuntimeException("Thread not interrupted " +
+                                                   "during wait()");
+                    }
+                }
+                synchronized (this) {
+                    Boolean sawEx = false;
+
+                    try {
+                        synchronized (interrupterLock) {
+                            interrupterLock.notify();
+                        }
+                        // System.out.println("Waiter calling wait(1000)");
+                        this.wait(1000);
+                    } catch (InterruptedException ex) {
+                        sawEx = true;
+                        // System.out.println("wait(1000): Waiter caught " + ex);
+                    }
+                    // System.out.println("wait(1000) finished");
+
+                    if (!sawEx) {
+                        throw new RuntimeException("Thread not interrupted " +
+                                                   "during wait(1000)");
+                    }
+                }
+                synchronized (this) {
+                    Boolean sawEx = false;
+
+                    try {
+                        synchronized (interrupterLock) {
+                            interrupterLock.notify();
+                        }
+                        // System.out.println("Waiter calling wait(1000, 5000)");
+                        this.wait(1000, 5000);
+                    } catch (InterruptedException ex) {
+                        sawEx = true;
+                        // System.out.println("wait(1000, 5000): Waiter caught " + ex);
+                    }
+                    // System.out.println("wait(1000, 5000) finished");
+
+                    if (!sawEx) {
+                        throw new RuntimeException("Thread not interrupted " +
+                                                   "during wait(1000, 5000)");
+                    }
+                }
+
+               //  System.out.println("Waiter returning");
+            }
+        }
+
+    private static Throwable errorException;
+    private static Thread testThread;
+
+    @MediumTest
+    public void testInterruptTest() throws Exception {
+
+
+            testThread = Thread.currentThread();
+            errorException = null;
+
+            Waiter waiter = new Waiter("InterruptTest Waiter");
+            Interrupter interrupter =
+                    new Interrupter("InterruptTest Interrupter", waiter);
+            interrupter.start();
+
+            try {
+                interrupter.join();
+                waiter.join();
+            } catch (InterruptedException ex) {
+                throw new RuntimeException("Test join interrupted.", ex);
+            }
+
+            if (errorException != null) {
+                throw new RuntimeException("InterruptTest failed",
+                                           errorException);
+            }
+
+
+
+
+    }
+
+     private static void deepWait(int depth, Object lock) {
+            synchronized (lock) {
+                if (depth > 0) {
+                    deepWait(depth - 1, lock);
+                } else {
+                    String threadName = Thread.currentThread().getName();
+                    try {
+                        // System.out.println(threadName + " waiting");
+                        lock.wait();
+                        // System.out.println(threadName + " done waiting");
+                    } catch (InterruptedException ex) {
+                        // System.out.println(threadName + " interrupted.");
+                    }
+                }
+            }
+        }
+
+        private class Worker extends Thread {
+            Object lock;
+            int id;
+
+            Worker(int id, Object lock) {
+                super("Worker(" + id + ")");
+                this.id = id;
+                this.lock = lock;
+            }
+
+            public void run() {
+                int iterations = 0;
+
+                while (MonitorTest.running) {
+                    MonitorTest.deepWait(id, lock);
+                    iterations++;
+                }
+                // System.out.println(getName() + " done after " + iterations + " iterations.");
+            }
+        }
+
+    private static Object commonLock = new Object();
+        private static Boolean running = false;
+
+
+    @LargeTest
+    public void testNestedMonitors() throws Exception {
+        final int NUM_WORKERS = 5;
+
+            Worker w[] = new Worker[NUM_WORKERS];
+            int i;
+
+            for (i = 0; i < NUM_WORKERS; i++) {
+                w[i] = new Worker(i * 2 - 1, new Object());
+            }
+
+            running = true;
+
+            // System.out.println("NestedMonitors: starting workers");
+            for (i = 0; i < NUM_WORKERS; i++) {
+                w[i].start();
+            }
+
+            try {
+                Thread.currentThread().sleep(1000);
+            } catch (InterruptedException ex) {
+               // System.out.println("Test sleep interrupted.");
+            }
+
+            for (i = 0; i < 100; i++) {
+                for (int j = 0; j < NUM_WORKERS; j++) {
+                    synchronized (w[j].lock) {
+                        w[j].lock.notify();
+                    }
+                }
+            }
+
+            // System.out.println("NesterMonitors: stopping workers");
+            running = false;
+            for (i = 0; i < NUM_WORKERS; i++) {
+                synchronized (w[i].lock) {
+                    w[i].lock.notifyAll();
+                }
+            }
+    }
+
+    private static class CompareAndExchange extends Thread {
+        static Object toggleLock = null;
+        static int toggle = -1;
+        static Boolean running = false;
+
+        public void run() {
+            toggleLock = new Object();
+            toggle = -1;
+
+            Worker w1 = new Worker(0, 1);
+            Worker w2 = new Worker(2, 3);
+            Worker w3 = new Worker(4, 5);
+            Worker w4 = new Worker(6, 7);
+
+            running = true;
+
+            // System.out.println("CompareAndExchange: starting workers");
+
+            w1.start();
+            w2.start();
+            w3.start();
+            w4.start();
+
+            try {
+                this.sleep(10000);
+            } catch (InterruptedException ex) {
+                // System.out.println(getName() + " interrupted.");
+            }
+
+            // System.out.println("MonitorTest: stopping workers");
+            running = false;
+
+            toggleLock = null;
+        }
+
+        class Worker extends Thread {
+            int i1;
+            int i2;
+
+            Worker(int i1, int i2) {
+                super("Worker(" + i1 + ", " + i2 + ")");
+                this.i1 = i1;
+                this.i2 = i2;
+            }
+
+            public void run() {
+                int iterations = 0;
+
+                /* Latch this because run() may set the static field to
+                 * null at some point.
+                 */
+                Object toggleLock = CompareAndExchange.toggleLock;
+
+                // System.out.println(getName() + " running");
+                try {
+                    while (CompareAndExchange.running) {
+                        synchronized (toggleLock) {
+                            int test;
+                            int check;
+
+                            if (CompareAndExchange.toggle == i1) {
+                                this.sleep(5 + i2);
+                                CompareAndExchange.toggle = test = i2;
+                            } else {
+                                this.sleep(5 + i1);
+                                CompareAndExchange.toggle = test = i1;
+                            }
+                            if ((check = CompareAndExchange.toggle) != test) {
+//                                System.out.println("Worker(" + i1 + ", " +
+//                                                   i2 + ") " + "test " + test +
+//                                                   " != toggle " + check);
+                                throw new RuntimeException(
+                                        "locked value changed");
+                            }
+                        }
+
+                        iterations++;
+                    }
+                } catch (InterruptedException ex) {
+                   // System.out.println(getName() + " interrupted.");
+                }
+
+//                System.out.println(getName() + " done after " +
+//                                   iterations + " iterations.");
+            }
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java
new file mode 100644
index 0000000..3462f97
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2005 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.unit_tests;
+import android.test.FrameworkTests;
+import android.test.suitebuilder.TestSuiteBuilder;
+
+import junit.framework.TestSuite;
+import junit.framework.TestCase;
+
+public class NewDatabasePerformanceTestSuite extends TestSuite {
+    public static TestSuite suite() {
+        TestSuite suite =
+          new TestSuite(NewDatabasePerformanceTestSuite.class.getName());
+
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           Insert1000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           InsertIndexed1000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           Select100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectStringComparison100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectIndex100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           InnerJoin100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           InnerJoinOneSide100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           InnerJoinNoIndex100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectSubQIndex100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectIndexStringComparison100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectInteger100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectString100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectIntegerIndex100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectIndexString100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectStringStartsWith100.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           DeleteIndexed1000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           Delete1000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           DeleteWhere1000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           DeleteIndexWhere1000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           UpdateIndexWhere1000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           UpdateWhere1000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           InsertInteger10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           InsertIntegerIndex10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           InsertString10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           InsertStringIndexed10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectStringStartsWith10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectStringIndexedStartsWith10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectInteger10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectIntegerIndexed10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectStringContains10000.class);
+        suite.addTestSuite(NewDatabasePerformanceTests.
+                           SelectStringIndexedContains10000.class);
+
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java
new file mode 100644
index 0000000..8644fbb
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.content.ContentValues;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.PerformanceTestCase;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.Random;
+
+/**
+ * Database Performance Tests
+ * 
+ */
+
+public class NewDatabasePerformanceTests {
+
+  // Edit this to change the test run times.  The original is 100.
+  final static int kMultiplier = 1;
+  
+  public static class PerformanceBase extends TestCase
+          implements PerformanceTestCase {
+    protected static final int CURRENT_DATABASE_VERSION = 42;
+    protected SQLiteDatabase mDatabase;
+    protected File mDatabaseFile;
+
+    public void setUp() {
+      mDatabaseFile = new File("/sdcard", "perf_database_test.db");
+      if (mDatabaseFile.exists()) {
+        mDatabaseFile.delete();
+      }
+      mDatabase =
+        SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(),
+            null);
+      assertTrue(mDatabase != null);
+      mDatabase.setVersion(CURRENT_DATABASE_VERSION);
+    }
+
+    public void tearDown() {
+      mDatabase.close();
+      mDatabaseFile.delete();
+    }
+
+    public boolean isPerformanceOnly() {
+      return true;
+    }
+
+    // These tests can only be run once.
+    public int startPerformance(Intermediates intermediates) {
+      return 0;
+    }
+
+    public String numberName(int number) {
+      String result = "";
+
+      if (number >= 1000) {
+        result += numberName((number / 1000)) + " thousand";
+        number = (number % 1000);
+
+        if (number > 0) result += " ";
+      }
+
+      if (number >= 100) {
+        result += ONES[(number / 100)] + " hundred";
+        number = (number % 100);
+
+        if (number > 0) result += " ";
+      }
+
+      if (number >= 20) {
+        result += TENS[(number / 10)];
+        number = (number % 10);
+
+        if (number > 0) result += " ";
+      }
+
+      if (number > 0) {
+        result += ONES[number];
+      }
+
+      return result;
+    }
+  }
+
+  /**
+   * Test 1000 inserts.
+   */
+
+  public static class Insert1000 extends PerformanceBase {
+    private static final int SIZE = 10 * kMultiplier;
+
+    private String[] statements = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        statements[i] =
+          "INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+          + numberName(r) + "')";
+      }
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.execSQL(statements[i]);
+      }
+    }
+  }
+
+  /**
+   * Test 1000 inserts into an indexed table.
+   */
+
+  public static class InsertIndexed1000 extends PerformanceBase {
+    private static final int SIZE = 10 * kMultiplier;
+
+    private String[] statements = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        statements[i] =
+          "INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+          + numberName(r) + "')";
+      }
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.execSQL(statements[i]);
+      }
+    }
+  }
+
+  /**
+   * 100 SELECTs without an index
+   */
+
+  public static class Select100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] = "b >= " + lower + " AND b < " + upper;
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase
+        .query("t1", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   * 100 SELECTs on a string comparison
+   */
+
+  public static class SelectStringComparison100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        where[i] = "c LIKE '" + numberName(i) + "'";
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase
+        .query("t1", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   * 100 SELECTs with an index
+   */
+
+  public static class SelectIndex100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] = "b >= " + lower + " AND b < " + upper;
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase
+        .query("t1", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  INNER JOIN without an index
+   */
+
+  public static class InnerJoin100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"t1.a"};
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase
+      .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+    }
+
+    public void testRun() {
+      mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null,
+          null, null, null, null);
+    }
+  }
+
+  /**
+   *  INNER JOIN without an index on one side
+   */
+
+  public static class InnerJoinOneSide100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"t1.a"};
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase
+      .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+    }
+
+    public void testRun() {
+      mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null,
+          null, null, null, null);
+    }
+  }
+
+  /**
+   *  INNER JOIN without an index on one side
+   */
+
+  public static class InnerJoinNoIndex100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"t1.a"};
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase
+      .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+    }
+
+    public void testRun() {
+      mDatabase.query("t1 INNER JOIN t2 ON t1.c = t2.c", COLUMNS, null,
+          null, null, null, null);
+    }
+  }
+
+  /**
+   *  100 SELECTs with subqueries. Subquery is using an index
+   */
+
+  public static class SelectSubQIndex100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"t1.a"};
+
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase
+      .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      mDatabase.execSQL("CREATE INDEX i2b ON t2(b)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] =
+          "t1.b IN (SELECT t2.b FROM t2 WHERE t2.b >= " + lower
+          + " AND t2.b < " + upper + ")";
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase
+        .query("t1", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  100 SELECTs on string comparison with Index
+   */
+
+  public static class SelectIndexStringComparison100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i3c ON t1(c)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        where[i] = "c LIKE '" + numberName(i) + "'";
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase
+        .query("t1", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  100 SELECTs on integer 
+   */
+
+  public static class SelectInteger100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"b"};
+
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  100 SELECTs on String
+   */
+
+  public static class SelectString100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"c"};
+
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  100 SELECTs on integer with index
+   */
+
+  public static class SelectIntegerIndex100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"b"};
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i1b on t1(b)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  100 SELECTs on String with index
+   */
+
+  public static class SelectIndexString100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"c"};      
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  100 SELECTs on String with starts with
+   */
+
+  public static class SelectStringStartsWith100 extends PerformanceBase {
+    private static final int SIZE = 1 * kMultiplier;
+    private static final String[] COLUMNS = {"c"};
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        where[i] = "c LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+      }
+
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase
+        .query("t1", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  1000 Deletes on an indexed table
+   */
+
+  public static class DeleteIndexed1000 extends PerformanceBase {
+    private static final int SIZE = 10 * kMultiplier;
+    private static final String[] COLUMNS = {"c"};
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i3c ON t1(c)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.delete("t1", null, null);
+      }
+    }
+  }
+
+  /**
+   *  1000 Deletes
+   */
+
+  public static class Delete1000 extends PerformanceBase {
+    private static final int SIZE = 10 * kMultiplier;
+    private static final String[] COLUMNS = {"c"};       
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.delete("t1", null, null);
+      }
+    }
+  }
+
+  /**
+   *  1000 DELETE's without an index with where clause 
+   */
+
+  public static class DeleteWhere1000 extends PerformanceBase {
+    private static final int SIZE = 10 * kMultiplier;
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] = "b >= " + lower + " AND b < " + upper;
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.delete("t1", where[i], null);
+      }
+    }
+  }
+
+  /**
+   *  1000 DELETE's with an index with where clause 
+   */
+
+  public static class DeleteIndexWhere1000 extends PerformanceBase {
+    private static final int SIZE = 10 * kMultiplier;
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] = "b >= " + lower + " AND b < " + upper;
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.delete("t1", where[i], null);
+      }
+    }
+  }
+
+  /**
+   *  1000 update's with an index with where clause 
+   */
+
+  public static class UpdateIndexWhere1000 extends PerformanceBase {
+    private static final int SIZE = 10 * kMultiplier;
+    private String[] where = new String[SIZE];
+    ContentValues[] mValues = new ContentValues[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] = "b >= " + lower + " AND b < " + upper;
+        ContentValues b = new ContentValues(1);
+        b.put("b", upper);
+        mValues[i] = b;
+
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.update("t1", mValues[i], where[i], null);
+      }
+    }
+  }
+
+  /**
+   *  1000 update's without an index with where clause 
+   */
+
+  public static class UpdateWhere1000 extends PerformanceBase {
+    private static final int SIZE = 10 * kMultiplier;       
+    private String[] where = new String[SIZE];
+    ContentValues[] mValues = new ContentValues[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] = "b >= " + lower + " AND b < " + upper;
+        ContentValues b = new ContentValues(1);
+        b.put("b", upper);
+        mValues[i] = b;
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.update("t1", mValues[i], where[i], null);
+      }
+    }
+  }
+
+  /**
+   *  10000 inserts for an integer 
+   */
+
+  public static class InsertInteger10000 extends PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    ContentValues[] mValues = new ContentValues[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        ContentValues b = new ContentValues(1);
+        b.put("a", r);
+        mValues[i] = b;
+      }
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.insert("t1", null, mValues[i]);
+      }
+    }
+  }
+
+  /**
+   *  10000 inserts for an integer -indexed table
+   */
+
+  public static class InsertIntegerIndex10000 extends PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    ContentValues[] mValues = new ContentValues[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a INTEGER)");
+      mDatabase.execSQL("CREATE INDEX i1a ON t1(a)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        ContentValues b = new ContentValues(1);
+        b.put("a", r);
+        mValues[i] = b;
+      }
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.insert("t1", null, mValues[i]);
+      }
+    }
+  }
+
+  /**
+   *  10000 inserts for a String 
+   */
+
+  public static class InsertString10000 extends PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    ContentValues[] mValues = new ContentValues[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        ContentValues b = new ContentValues(1);
+        b.put("a", numberName(r));
+        mValues[i] = b;
+      }
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.insert("t1", null, mValues[i]);
+      }
+    }
+  }
+
+  /**
+   *  10000 inserts for a String - indexed table 
+   */
+
+  public static class InsertStringIndexed10000 extends PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;       
+    ContentValues[] mValues = new ContentValues[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t1(a VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i1a ON t1(a)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        ContentValues b = new ContentValues(1);
+        b.put("a", numberName(r));
+        mValues[i] = b; 
+      }
+    }
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.insert("t1", null, mValues[i]);
+      }
+    }
+  }
+
+
+  /**
+   *  10000 selects for a String -starts with
+   */
+
+  public static class SelectStringStartsWith10000 extends PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    private static final String[] COLUMNS = {"t3.a"};
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t3 VALUES('"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+      }
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  10000 selects for a String - indexed table -starts with
+   */
+
+  public static class SelectStringIndexedStartsWith10000 extends
+  PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    private static final String[] COLUMNS = {"t3.a"};
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i3a ON t3(a)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t3 VALUES('"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+      }                              
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  10000 selects for an integer -
+   */
+
+  public static class SelectInteger10000 extends PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    private static final String[] COLUMNS = {"t4.a"};
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t4(a INTEGER)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")");
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] = "a >= " + lower + " AND a < " + upper;
+      }
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t4", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  10000 selects for an integer -indexed table
+   */
+
+  public static class SelectIntegerIndexed10000 extends PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    private static final String[] COLUMNS = {"t4.a"};
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t4(a INTEGER)");
+      mDatabase.execSQL("CREATE INDEX i4a ON t4(a)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")");
+
+        int lower = i * 100;
+        int upper = (i + 10) * 100;
+        where[i] = "a >= " + lower + " AND a < " + upper;
+      }
+
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t4", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+
+  /**
+   *  10000 selects for a String - contains 'e'
+   */
+
+  public static class SelectStringContains10000 extends PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    private static final String[] COLUMNS = {"t3.a"};
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t3 VALUES('"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        where[i] = "a LIKE '*e*'";
+
+      }                              
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  /**
+   *  10000 selects for a String - contains 'e'-indexed table
+   */
+
+  public static class SelectStringIndexedContains10000 extends
+  PerformanceBase {
+    private static final int SIZE = 100 * kMultiplier;
+    private static final String[] COLUMNS = {"t3.a"};
+    private String[] where = new String[SIZE];
+
+    @Override
+    public void setUp() {
+      super.setUp();
+      Random random = new Random(42);
+
+      mDatabase
+      .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+      mDatabase.execSQL("CREATE INDEX i3a ON t3(a)");
+
+      for (int i = 0; i < SIZE; i++) {
+        int r = random.nextInt(100000);
+        mDatabase.execSQL("INSERT INTO t3 VALUES('"
+            + numberName(r) + "')");
+      }
+
+      for (int i = 0; i < SIZE; i++) {
+        where[i] = "a LIKE '*e*'";
+
+      }                              
+    }        
+
+    public void testRun() {
+      for (int i = 0; i < SIZE; i++) {
+        mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+      }
+    }
+  }
+
+  public static final String[] ONES =
+  {"zero", "one", "two", "three", "four", "five", "six", "seven",
+    "eight", "nine", "ten", "eleven", "twelve", "thirteen",
+    "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
+  "nineteen"};
+
+  public static final String[] TENS =
+  {"", "ten", "twenty", "thirty", "forty", "fifty", "sixty",
+    "seventy", "eighty", "ninety"};
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java b/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java
new file mode 100644
index 0000000..d4d2a82
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import com.google.android.net.ParentalControl;
+import com.google.android.net.ParentalControlState;
+
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+public class ParentalControlTest extends AndroidTestCase {
+
+    private boolean mOnResultCalled = false;
+
+    public class Callback implements ParentalControl.Callback {
+        public void onResult(ParentalControlState state) {
+            synchronized (ParentalControlTest.class) {
+                mOnResultCalled = true;
+                ParentalControlTest.class.notifyAll();
+            }
+        }
+    }
+
+    @SmallTest
+    public void testParentalControlCallback() {
+        synchronized (ParentalControlTest.class) {
+            ParentalControl.getParentalControlState(new Callback(), null);
+            try {
+                long start = SystemClock.uptimeMillis();
+                ParentalControlTest.class.wait(20 * 1000);
+                long end = SystemClock.uptimeMillis();
+                Log.d("AndroidTests", "ParentalControlTest callback took " + (end-start) + " ms.");
+            } catch (InterruptedException ex) {
+            }
+        }
+
+        Assert.assertTrue(mOnResultCalled);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java
new file mode 100644
index 0000000..9e54540
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.os.Debug;
+import junit.framework.Assert;
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+import org.apache.harmony.dalvik.NativeTestTarget;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PerformanceTests {
+    public static String[] children() {
+        return new String[] {
+                //StringEquals2.class.getName(),
+                //StringEquals10.class.getName(),
+                //StringEquals20.class.getName(),
+                //StringEquals200.class.getName(),
+                //StringEquals200U.class.getName(),
+                //StringCompareTo10.class.getName(),
+                //StringCompareTo200.class.getName(),
+                StringLength.class.getName(),
+                StringCrawl.class.getName(),
+                Ackermann.class.getName(),
+                AddTest.class.getName(),
+//                AddMemberVariableTest.class.getName(),
+                ArrayListIterator.class.getName(),
+                BoundsCheckTest.class.getName(),
+//                EmptyClassBaseTest.class.getName(),
+                EmptyJniStaticMethod0.class.getName(),
+                EmptyJniStaticMethod6.class.getName(),
+                EmptyJniStaticMethod6L.class.getName(),
+                FibonacciFast.class.getName(),
+                FibonacciSlow.class.getName(),
+//                LoopTests.class.getName(),
+//                HashMapTest.class.getName(),
+//                InterfaceTests.class.getName(),
+                LocalVariableAccess.class.getName(),
+                MemeberVariableAccess.class.getName(),
+                NestedLoop.class.getName(),
+//                StringConcatenationTests.class.getName(),
+//                ArrayListBase.class.getName(),
+                SynchronizedGetAndSetInt.class.getName(),
+
+                /* this will not work on JamVM -- lacks atomic ops */
+                AtomicGetAndSetInt.class.getName(),
+        };
+    }
+
+    public static class SizeTest {
+        private int mSize;
+
+        public SizeTest(int size) {
+            mSize = size;
+        }
+
+        public int size() {
+            return mSize;
+        }
+    }
+
+    public static class LocalVariableAccess extends PerformanceTestBase {
+        private static final int ITERATIONS = 100000;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 20);
+            return 0;
+        }
+
+        public void testRun() {
+            boolean variable = false;
+            boolean local = true;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                local = variable;
+                local = variable;
+                local = variable;
+                local = variable;
+                local = variable; // 5
+                local = variable;
+                local = variable;
+                local = variable;
+                local = variable;
+                local = variable; // 10
+                local = variable;
+                local = variable;
+                local = variable;
+                local = variable;
+                local = variable; // 15
+                local = variable;
+                local = variable;
+                local = variable;
+                local = variable;
+                local = variable; // 20
+            }
+        }
+    }
+
+    /* This test is intentionally misspelled. Please do not rename it. Thanks! */
+    public static class MemeberVariableAccess extends PerformanceTestBase {
+        private static final int ITERATIONS = 100000;
+
+        public volatile boolean mMember = false;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 20);
+            return 0;
+        }
+
+        public void testRun() {
+            boolean local = true;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                local = mMember;
+                local = mMember;
+                local = mMember;
+                local = mMember;
+                local = mMember; // 5
+                local = mMember;
+                local = mMember;
+                local = mMember;
+                local = mMember;
+                local = mMember; // 10
+                local = mMember;
+                local = mMember;
+                local = mMember;
+                local = mMember;
+                local = mMember; // 15
+                local = mMember;
+                local = mMember;
+                local = mMember;
+                local = mMember;
+                local = mMember; // 20
+            }
+        }
+    }
+
+    public static class ArrayListIterator extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+        private ArrayList mList;
+        private String[] mKeys;
+        private Iterator mIterator;
+
+        public void setUp() throws Exception {
+            super.setUp();
+            mList = new ArrayList();
+            mKeys = new String[ITERATIONS];
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                mKeys[i] = Integer.toString(i, 16);
+                mList.add(mKeys[i]);
+            }
+        }
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS);
+            return 0;
+        }
+
+        public void testRun() {
+            mIterator = mList.iterator();
+            while (mIterator.hasNext()) {
+                mIterator.next();
+            }
+        }
+    }
+
+    public static class Ackermann extends PerformanceTestBase {
+        public static final int ITERATIONS = 100;
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS);
+            return 0;
+        }
+
+        public void testRun() {
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                ackermann(3, 13);
+            }
+        }
+
+        private int ackermann(int m, int n) {
+            if (m == 0)
+                return n + 1;
+            if (n == 0)
+                return ackermann(m - 1, 1);
+            return ackermann(m, n - 1);
+        }
+    }
+
+    public static class FibonacciSlow extends PerformanceTestBase {
+        public void setUp() throws Exception {
+            super.setUp();
+            Assert.assertEquals(0, fibonacci(0));
+            Assert.assertEquals(1, fibonacci(1));
+            Assert.assertEquals(1, fibonacci(2));
+            Assert.assertEquals(2, fibonacci(3));
+            Assert.assertEquals(6765, fibonacci(20));
+        }
+
+        public void tearDown() {
+        }
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            return 0;
+        }
+
+        public void testRun() {
+            fibonacci(20);
+        }
+
+        private long fibonacci(long n) {
+            if (n == 0)
+                return 0;
+            if (n == 1)
+                return 1;
+            return fibonacci(n - 2) + fibonacci(n - 1);
+        }
+    }
+
+    public static class FibonacciFast extends PerformanceTestBase {
+        public void setUp() throws Exception {
+            super.setUp();
+            Assert.assertEquals(0, fibonacci(0));
+            Assert.assertEquals(1, fibonacci(1));
+            Assert.assertEquals(1, fibonacci(2));
+            Assert.assertEquals(2, fibonacci(3));
+            Assert.assertEquals(6765, fibonacci(20));
+        }
+
+        public void tearDown() {
+        }
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            return 0;
+        }
+
+        public void testRun() {
+            fibonacci(5000);
+        }
+
+        private long fibonacci(long n) {
+            if (n == 0)
+                return 0;
+            if (n == 1)
+                return 1;
+
+            int x = 0;
+            int y = 1;
+            for (int i = 0; i < n - 1; i++) {
+                y = y + x;
+                x = y - x;
+            }
+
+            return y;
+        }
+    }
+
+    public static class HashMapTest extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+        private HashMap mMap;
+        private String[] mKeys;
+
+        public void setUp() throws Exception {
+            super.setUp();
+            mMap = new HashMap();
+            mKeys = new String[ITERATIONS];
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                mKeys[i] = Integer.toString(i, 16);
+                mMap.put(mKeys[i], i);
+            }
+        }
+
+        public void tearDown() {
+        }
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS);
+            return 0;
+        }
+
+        public void testHashMapContainsKey() {
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                mMap.containsKey(mKeys[i]);
+            }
+        }
+
+        public void testHashMapIterator() {
+            Iterator iterator;
+
+            iterator = mMap.entrySet().iterator();
+            while (iterator.hasNext()) {
+                iterator.next();
+            }
+        }
+
+        public void testHashMapPut() {
+            HashMap map = new HashMap();
+            String[] keys = mKeys;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                map.put(keys[i], i);
+            }
+        }
+    }
+
+    interface IA {
+        void funcA0();
+        void funcA1();
+        void funcA2();
+        void funcA3();
+    }
+    interface IAB extends IA {
+        void funcAB0();
+        void funcAB1();
+        void funcAB2();
+        void funcAB3();
+    }
+    interface IABC extends IAB {
+        void funcABC0();
+        void funcABC1();
+        void funcABC2();
+        void funcABC3();
+    }
+    interface IB {
+        void funcB0();
+        void funcB1();
+        void funcB2();
+        void funcB3();
+    }
+    interface IC {
+        void funcC0();
+        void funcC1();
+        void funcC2();
+        void funcC3();
+    }
+
+    static class Alphabet implements Cloneable, IB, IABC, IC, Runnable {
+        public void funcA0() {
+        }
+        public void funcA1() {
+        }
+        public void funcA2() {
+        }
+        public void funcA3() {
+        }
+        public void funcAB0() {
+        }
+        public void funcAB1() {
+        }
+        public void funcAB2() {
+        }
+        public void funcAB3() {
+        }
+        public void funcABC0() {
+        }
+        public void funcABC1() {
+        }
+        public void funcABC2() {
+        }
+        public void funcABC3() {
+        }
+        public void funcB0() {
+        }
+        public void funcB1() {
+        }
+        public void funcB2() {
+        }
+        public void funcB3() {
+        }
+        public void funcC0() {
+        }
+        public void funcC1() {
+        }
+        public void funcC2() {
+        }
+        public void funcC3() {
+        }
+        public void run() {
+        }
+    };
+
+    public static class InterfaceTests extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        /* call method directly */
+        public void testInterfaceCalls0() {
+            Alphabet alpha = new Alphabet();
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                alpha.funcABC1();
+                alpha.funcABC1();
+                alpha.funcABC1();
+                alpha.funcABC1();
+                alpha.funcABC1();
+                alpha.funcABC1();
+                alpha.funcABC1();
+                alpha.funcABC1();
+                alpha.funcABC1();
+                alpha.funcABC1();
+            }
+        }
+
+       /* call method through interface reference */
+        public void testInterfaceCalls1() {
+            Alphabet alpha = new Alphabet();
+            IABC iabc = alpha;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                iabc.funcABC1();
+                iabc.funcABC1();
+                iabc.funcABC1();
+                iabc.funcABC1();
+                iabc.funcABC1();
+                iabc.funcABC1();
+                iabc.funcABC1();
+                iabc.funcABC1();
+                iabc.funcABC1();
+                iabc.funcABC1();
+            }
+        }
+
+        public void testInstanceOfTrivial() {
+            Alphabet alpha = new Alphabet();
+            IABC iabc = alpha;
+            boolean val;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+                val = iabc instanceof Alphabet;
+            }
+        }
+
+        public void testInstanceOfInterface() {
+            Alphabet alpha = new Alphabet();
+            IABC iabc = alpha;
+            boolean val;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+                val = iabc instanceof IA;
+            }
+        }
+
+        public void testInstanceOfNot() {
+            Alphabet alpha = new Alphabet();
+            IABC iabc = alpha;
+            boolean val;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+                val = iabc instanceof EmptyInterface;
+            }
+        }
+    }
+
+    public static class NestedLoop extends PerformanceTestBase {
+        private static final int ITERATIONS = 10;
+        private static final int LOOPS = 5;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * LOOPS);
+            return 0;
+        }
+
+        public void testRun() {
+            int x = 0;
+            for (int a = 0; a < ITERATIONS; a++) {
+                for (int b = 0; b < ITERATIONS; b++) {
+                    for (int c = 0; c < ITERATIONS; c++) {
+                        for (int d = 0; d < ITERATIONS; d++) {
+                            for (int e = 0; e < ITERATIONS; e++) {
+                                x++;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public static class StringConcatenationTests extends PerformanceTestBase {
+        private static final int ITERATIONS = 1000;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS);
+            return 0;
+        }
+
+        public void testStringConcatenation1() {
+            StringBuffer buffer = new StringBuffer();
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                buffer.append("Hello World!\n");
+            }
+            buffer = null;
+        }
+
+        public void testStringConcatenation2() {
+            String string = "";
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                string += "Hello World!\n";
+            }
+            string = null;
+        }
+    }
+
+    public static class StringLength extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+        private static final String TEST_STRING = "This is the string we use for testing..."; // 40 chars
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testRun() {
+            String testStr = TEST_STRING;
+            int length;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                length = testStr.length();
+                length = testStr.length();
+                length = testStr.length();
+                length = testStr.length();
+                length = testStr.length();
+                length = testStr.length();
+                length = testStr.length();
+                length = testStr.length();
+                length = testStr.length();
+                length = testStr.length();
+            }
+        }
+    }
+
+    public static class EmptyJniStaticMethod0 extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testRun() {
+            int a, b, c, d, e, f;
+
+            a = b = c = d = e = f = 0;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+            }
+        }
+    }
+    public static class EmptyJniStaticMethod6 extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testRun() {
+            int a, b, c, d, e, f;
+
+            a = b = c = d = e = f = 0;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+            }
+        }
+    }
+    public static class EmptyJniStaticMethod6L extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testRun() {
+            String a = null;
+            String[] b = null;
+            int[][] c = null;
+            Object d = null;
+            Object[] e = null;
+            Object[][][][] f = null;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+            }
+        }
+    }
+
+    public static class StringCrawl extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+        private static final String TEST_STRING = "This is the string we use for testing..."; // 40 chars
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * TEST_STRING.length());
+            return 0;
+        }
+
+        public void testRun() {
+            String testStr = TEST_STRING;
+            char ch;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                /* this is the wrong way to walk through a string */
+                for (int j = 0; j < testStr.length(); j++) {
+                    ch = testStr.charAt(j);
+                }
+            }
+        }
+    }
+
+    public static class AddTest extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 20);
+            return 0;
+        }
+
+        public void testRun() {
+            int j = 0;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+            }
+        }
+    }
+
+    public static class AddMemberVariableTest extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+        private int j;
+
+        public void setUp() throws Exception {
+           super.setUp();
+           j = 0;
+        }
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testAddMemberVariableTest() {
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+                j++;
+            }
+        }
+
+        public void testAddMemberVariableInMethodTest() {
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                add();
+                add();
+                add();
+                add();
+                add();
+                add();
+                add();
+                add();
+                add();
+                add();
+            }
+        }
+
+        public void add() {
+            j++;
+        }
+    }
+
+    private interface EmptyInterface {
+        public void emptyVirtual();
+
+    }
+
+    private static class EmptyClass implements EmptyInterface {
+        public void emptyVirtual() {
+        }
+
+        public static void emptyStatic() {
+        }
+    }
+
+    public static class EmptyClassBaseTest extends PerformanceTestBase {
+        protected EmptyInterface mEmptyInterface;
+        protected EmptyClass mEmptyClass;
+
+        public void setUp() throws Exception {
+            super.setUp();
+            mEmptyClass = new EmptyClass();
+            mEmptyInterface = mEmptyClass;
+        }
+        private static final int ITERATIONS = 10000;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testEmptyVirtualMethod() {
+            //EmptyClass emtpyClass = mEmptyClass;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+                mEmptyClass.emptyVirtual();
+            }
+        }
+
+        public void testEmptyVirtualMethodTestInLocal() {
+            EmptyClass empty = mEmptyClass;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+                empty.emptyVirtual();
+            }
+        }
+
+    public void testEmptyStaticMethod () {
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+                EmptyClass.emptyStatic();
+            }
+        }
+
+    public void testEmptyJniStaticMethod0() {
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+                NativeTestTarget.emptyJniStaticMethod0();
+            }
+        }
+
+    public void testEmptyJniStaticMethod6() {
+            int a, b, c, d, e, f;
+
+            a = b = c = d = e = f = 0;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+                NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+            }
+        }
+
+    public void testEmptyInternalStaticMethod() {
+            /*
+             * The method called is a VM-internal method with no extra
+             * wrapping.
+             */
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+                NativeTestTarget.emptyInternalStaticMethod();
+            }
+        }
+
+    public void testEmptyInlineStaticMethod() {
+            /*
+             * The method called is a VM-internal method that gets
+             * specially "inlined" in a bytecode transformation.
+             */
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+                NativeTestTarget.emptyInlineMethod();
+            }
+        }
+
+    public void testEmptyInterfaceMethodTest() {
+            EmptyInterface emptyInterface = mEmptyInterface;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+                emptyInterface.emptyVirtual();
+            }
+        }
+    }
+
+    public static class LoopTests extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+        private SizeTest mSizeTest = new SizeTest(ITERATIONS);
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS);
+            return 0;
+        }
+
+        public void testForLoopTest() {
+            int i = 0;
+            for (; i < 10000; i++) {
+            }
+        }
+
+        public void testWhileLoopTest() {
+            int i = 0;
+
+            while (i < 10000) {
+                i++;
+            }
+        }
+
+        public void testForLoopSizeCalledInside() {
+            for (int i = 0; i < mSizeTest.size(); i++) {
+            }
+        }
+
+        public void testForLoopSizeCalledOutside() {
+            final int size = mSizeTest.size();
+            for (int i = 0; i < size; i++) {
+            }
+        }
+    }
+
+    public static class BoundsCheckTest extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testRun() {
+            int[] data = new int[1];
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                data[0] = i;
+                data[0] = i;
+                data[0] = i;
+                data[0] = i;
+                data[0] = i;
+                data[0] = i;
+                data[0] = i;
+                data[0] = i;
+                data[0] = i;
+                data[0] = i;
+            }
+        }
+    }
+
+    public static class ArrayListBase extends PerformanceTestBase {
+        public void setUp() throws Exception {
+            super.setUp();
+            mList = new ArrayList();
+            mList.add(0);
+            mList.add(1);
+            mList.add(2);
+            mList.add(3);
+            mList.add(4);
+            mList.add(5);
+            mList.add(6);
+            mList.add(7);
+            mList.add(8);
+            mList.add(9);
+        }
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(100);
+            return 0;
+        }
+
+        ArrayList<Integer> mList;
+
+        public void testForArrayList() {
+            int i = 0;
+            int res = 0;
+            for (; i < 100; i++) {
+                for (int j = 0; j < mList.size(); j++) {
+                    res += mList.get(j);
+                }
+            }
+        }
+
+        public void testForLocalArrayList() {
+            int i = 0;
+            int res = 0;
+            for (; i < 100; i++) {
+                final List<Integer> list = mList;
+                final int N = list.size();
+                for (int j = 0; j < N; j++) {
+                    res += list.get(j);
+                }
+            }
+        }
+
+        public void testForEachArrayList() {
+            int i = 0;
+            int res = 0;
+            for (; i < 100; i++) {
+                for (Integer v : mList) {
+                    res += v;
+                }
+            }
+        }
+    }
+
+    public static class SynchronizedGetAndSetInt extends PerformanceTestBase {
+        private static final int ITERATIONS = 100000;
+
+        public int mMember = 0;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS);
+            return 0;
+        }
+
+        public void testRun() {
+            int result = 0;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                synchronized (this) {
+                    result = mMember;
+                    mMember = i;
+                }
+            }
+        }
+    }
+
+    public static class AtomicGetAndSetInt extends PerformanceTestBase {
+        private static final int ITERATIONS = 100000;
+
+        public AtomicInteger mMember = new AtomicInteger(0);
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS);
+            return 0;
+        }
+
+        public void testRun() {
+            int result = 0;
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                result = mMember.getAndSet(i);
+            }
+        }
+    }
+
+    public static abstract class StringEquals extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+
+        protected String mString1, mString2;
+        public void setUp() throws Exception {
+          super.setUp();
+        }
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testRun() {
+            String string1 = mString1;
+            String string2 = mString2;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                string1.equals(string2);
+                string1.equals(string2);
+                string1.equals(string2);
+                string1.equals(string2);
+                string1.equals(string2);
+                string1.equals(string2);
+                string1.equals(string2);
+                string1.equals(string2);
+                string1.equals(string2);
+                string1.equals(string2);
+            }
+        }
+    }
+
+    public static class StringEquals2 extends StringEquals {
+        public void setUp() throws Exception {
+            mString1 = "01";
+            mString2 = "0x";
+        }
+    }
+    public static class StringEquals10 extends StringEquals {
+        public void setUp() throws Exception {
+            mString1 = "0123456789";
+            mString2 = "012345678x";
+        }
+    }
+    public static class StringEquals20 extends StringEquals {
+        public void setUp() throws Exception {
+            mString1 = "01234567890123456789";
+            mString2 = "0123456789012345678x";
+        }
+    }
+
+    public static class StringEquals200 extends StringEquals {
+        public void setUp() throws Exception {
+            mString1 = "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789";
+            mString2 = "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "012345678901234567890123456789012345678x";
+        }
+    }
+    public static class StringEquals200U extends StringEquals {
+        /* make one of the strings non-word aligned (bad memcmp case) */
+        public void setUp() throws Exception {
+            String tmpStr;
+            mString1 = "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789";
+            tmpStr = "z0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "012345678901234567890123456789012345678x";
+            mString2 = tmpStr.substring(1);
+        }
+    }
+
+    public static abstract class StringCompareTo extends PerformanceTestBase {
+        private static final int ITERATIONS = 10000;
+
+        protected String mString1, mString2;
+
+        public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+            intermediates.setInternalIterations(ITERATIONS * 10);
+            return 0;
+        }
+
+        public void testRun() {
+            String string1 = mString1;
+            String string2 = mString2;
+
+            for (int i = ITERATIONS - 1; i >= 0; i--) {
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+                string1.compareTo(string2);
+            }
+        }
+    }
+    public static class StringCompareTo10 extends StringCompareTo {
+        public void setUp() throws Exception {
+            mString1 = "0123456789";
+            mString2 = "012345678x";
+        }
+    }
+    public static class StringCompareTo200 extends StringCompareTo {
+        public void setUp() throws Exception {
+            mString1 = "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789";
+            mString2 = "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "0123456789012345678901234567890123456789"
+                    + "012345678901234567890123456789012345678x";
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java b/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java
new file mode 100644
index 0000000..8f55044
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.util.Regex;
+import junit.framework.TestCase;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class RegexTest extends TestCase {
+
+    @SmallTest
+    public void testTldPattern() throws Exception {
+        boolean t;
+
+        t = Regex.TOP_LEVEL_DOMAIN_PATTERN.matcher("com").matches();
+        assertTrue("Missed valid TLD", t);
+
+        t = Regex.TOP_LEVEL_DOMAIN_PATTERN.matcher("xer").matches();
+        assertFalse("Matched invalid TLD!", t);
+    }
+
+    @SmallTest
+    public void testUrlPattern() throws Exception {
+        boolean t;
+
+        t = Regex.WEB_URL_PATTERN.matcher("http://www.google.com").matches();
+        assertTrue("Valid URL", t);
+
+        t = Regex.WEB_URL_PATTERN.matcher("ftp://www.example.com").matches();
+        assertFalse("Matched invalid protocol", t);
+
+        t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080").matches();
+        assertTrue("Didn't match valid URL with port", t);
+
+        t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080/?foo=bar").matches();
+        assertTrue("Didn't match valid URL with port and query args", t);
+
+        t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080/~user/?foo=bar").matches();
+        assertTrue("Didn't match valid URL with ~", t);
+    }
+
+    @SmallTest
+    public void testIpPattern() throws Exception {
+        boolean t;
+
+        t = Regex.IP_ADDRESS_PATTERN.matcher("172.29.86.3").matches();
+        assertTrue("Valid IP", t);
+
+        t = Regex.IP_ADDRESS_PATTERN.matcher("1234.4321.9.9").matches();
+        assertFalse("Invalid IP", t);
+    }
+
+    @SmallTest
+    public void testDomainPattern() throws Exception {
+        boolean t;
+
+        t = Regex.DOMAIN_NAME_PATTERN.matcher("mail.example.com").matches();
+        assertTrue("Valid domain", t);
+
+        t = Regex.DOMAIN_NAME_PATTERN.matcher("__+&42.xer").matches();
+        assertFalse("Invalid domain", t);
+    }
+
+    @SmallTest
+    public void testPhonePattern() throws Exception {
+        boolean t;
+
+        t = Regex.PHONE_PATTERN.matcher("(919) 555-1212").matches();
+        assertTrue("Valid phone", t);
+
+        t = Regex.PHONE_PATTERN.matcher("2334 9323/54321").matches();
+        assertFalse("Invalid phone", t);
+
+        String[] tests = {
+                "Me: 16505551212 this\n",
+                "Me: 6505551212 this\n",
+                "Me: 5551212 this\n",
+
+                "Me: 1-650-555-1212 this\n",
+                "Me: (650) 555-1212 this\n",
+                "Me: +1 (650) 555-1212 this\n",
+                "Me: +1-650-555-1212 this\n",
+                "Me: 650-555-1212 this\n",
+                "Me: 555-1212 this\n",
+
+                "Me: 1.650.555.1212 this\n",
+                "Me: (650) 555.1212 this\n",
+                "Me: +1 (650) 555.1212 this\n",
+                "Me: +1.650.555.1212 this\n",
+                "Me: 650.555.1212 this\n",
+                "Me: 555.1212 this\n",
+
+                "Me: 1 650 555 1212 this\n",
+                "Me: (650) 555 1212 this\n",
+                "Me: +1 (650) 555 1212 this\n",
+                "Me: +1 650 555 1212 this\n",
+                "Me: 650 555 1212 this\n",
+                "Me: 555 1212 this\n",
+        };
+
+        for (String test : tests) {
+            Matcher m = Regex.PHONE_PATTERN.matcher(test);
+
+            assertTrue("Valid phone " + test, m.find());
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java
new file mode 100644
index 0000000..ce0b53d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.android.internal.telephony.gsm.GsmAlphabet;
+import com.android.internal.telephony.gsm.SmsHeader;
+import com.android.internal.util.HexDump;
+import android.telephony.gsm.SmsMessage;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.Iterator;
+
+public class SMSTest extends AndroidTestCase {
+
+    @SmallTest
+    public void testOne() throws Exception {
+        String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E";
+
+        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertEquals("+14155551212", sms.getServiceCenterAddress());
+        assertEquals("+16505551111", sms.getOriginatingAddress());
+        assertEquals("Test", sms.getMessageBody());
+        //assertTrue(sms.scTimeMillis == 1152223383000L);
+
+        pdu = "07914151551512f2040B916105551511f100036060924180008A0DA"
+                + "8695DAC2E8FE9296A794E07";
+
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertEquals("+14155551212", sms.getServiceCenterAddress());
+        assertEquals("+16505551111", sms.getOriginatingAddress());
+        assertEquals("(Subject)Test", sms.getMessageBody());
+
+        /*        lines[0] = "+CMT: ,45";
+                lines[1] = "07914140279510F6440A8111110301003BF56070624111958A8C0B05040B8423F"
+                         + "000033702010106276170706C69636174696F6E2F766E642E7761702E6D6D732D"
+                         + "6D65737361676500AF848D018BB4848C8298524D66616E304A6D7135514141416"
+                         + "57341414141546741414E4E304141414141008D908918802B3136353032343836"
+                         + "3137392F545950453D504C4D4E009646573A20008A808E0222C788058103093A7"
+                         + "F836874";
+
+                sms = SMSMessage.createFromPdu(mContext, lines);
+        */
+
+        pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F"
+                + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D"
+                + "6D65737361676500AF848D0185B4848C8298524E453955304A6D7135514141426"
+                + "66C414141414D7741414236514141414141008D908918802B3135313232393737"
+                + "3638332F545950453D504C4D4E008A808E022B918805810306977F83687474703"
+                + "A2F2F36";
+
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        SmsHeader header = sms.getUserDataHeader();
+        assertNotNull(header);
+
+        Iterator<SmsHeader.Element> elements = header.getElements().iterator();
+        assertNotNull(elements);
+
+
+        pdu = "07914140279510F6440A8111110301003BF56080207130238A3B0B05040B8423F"
+                + "000032A0202362E3130322E3137312E3135302F524E453955304A6D7135514141"
+                + "42666C414141414D774141423651414141414100";
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        header = sms.getUserDataHeader();
+        assertNotNull(header);
+
+        elements = header.getElements().iterator();
+        assertNotNull(elements);
+
+        /*
+        * UCS-2 encoded SMS
+        */
+
+        pdu = "07912160130300F4040B914151245584F600087010807121352B10212200A900AE00680065006C006C006F";
+
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+        assertEquals("\u2122\u00a9\u00aehello", sms.getMessageBody());
+
+        // Entire alphabet (minus the escape character)
+
+        /****
+         lines[0] = "+CMT: ";
+         lines[1] = "0001000A8114455245680000808080604028180E888462C168381E90886442A9582E988C06C0E9783EA09068442A994EA8946AC56AB95EB0986C46ABD96EB89C6EC7EBF97EC0A070482C1A8FC8A472C96C3A9FD0A8744AAD5AAFD8AC76CBED7ABFE0B0784C2E9BCFE8B47ACD6EBBDFF0B87C4EAFDBEFF8BC7ECFEFFBFF";
+         sms = SMSMessage.createFromPdu(mContext, lines);
+
+         System.out.println("full alphabet message body len: "
+         + sms.getMessageBody().length());
+
+         System.out.println("'" + sms.getMessageBody() +"'");
+
+         assertTrue(sms.getMessageBody().length() == 128);
+         ****/
+
+        /*
+        * Multi-part text SMS with data in septets
+        */
+        pdu = "07916163838408F6440B816105224431F700007060217175830AA0050003"
+                + "00020162B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
+                + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
+                + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
+                + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
+                + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562";
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+        assertEquals(sms.getMessageBody(),
+                "1111111111111111111111111111111111111111"
+                        + "1111111111111111111111111111111111111111"
+                        + "1111111111111111111111111111111111111111"
+                        + "111111111111111111111111111111111");
+
+        pdu = "07916163838408F6440B816105224431F700007060217185000A23050003"
+                + "00020262B1582C168BC96432994C2693C96432994C2693C96432990C";
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+        assertEquals("1111111222222222222222222222", sms.getMessageBody());
+    }
+
+    @SmallTest
+    public void testCPHSVoiceMail() throws Exception {
+        // "set MWI flag"
+
+        String pdu = "07912160130310F20404D0110041006060627171118A0120";
+
+        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertTrue(sms.isReplace());
+        assertEquals("_@", sms.getOriginatingAddress());
+        assertEquals(" ", sms.getMessageBody());
+        assertTrue(sms.isMWISetMessage());
+
+        // "clear mwi flag"
+
+        pdu = "07912160130310F20404D0100041006021924193352B0120";
+
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertTrue(sms.isMWIClearMessage());
+
+        // "clear MWI flag"
+
+        pdu = "07912160130310F20404D0100041006060627161058A0120";
+
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+//        System.out.println("originating address: "
+//                + (int) (sms.getOriginatingAddress().charAt(0)) + " "
+//                + (int) (sms.getOriginatingAddress().charAt(1)));
+
+        assertTrue(sms.isReplace());
+        assertEquals("\u0394@", sms.getOriginatingAddress());
+        assertEquals(" ", sms.getMessageBody());
+        assertTrue(sms.isMWIClearMessage());
+    }
+
+    @SmallTest
+    public void testCingularVoiceMail() throws Exception {
+        // "set MWI flag"
+
+        String pdu = "07912180958750F84401800500C87020026195702B06040102000200";
+        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertTrue(sms.isMWISetMessage());
+        assertTrue(sms.isMwiDontStore());
+
+        // "clear mwi flag"
+
+        pdu = "07912180958750F84401800500C07020027160112B06040102000000";
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertTrue(sms.isMWIClearMessage());
+        assertTrue(sms.isMwiDontStore());
+    }
+
+//    public void testTwo() throws Exception {
+//        // FIXME need an SMS-SUBMIT test
+//
+//        System.out.println(
+//                "SMS SUBMIT: " + SmsMessage.getSubmitPdu(null, "+14155551212", "test", false));
+//    }
+
+    @SmallTest
+    public void testEmailGateway() throws Exception {
+        // email gateway sms test
+        String pdu = "07914151551512f204038105f300007011103164638a28e6f71b50c687db" +
+                "7076d9357eb7412f7a794e07cdeb6275794c07bde8e5391d247e93f3";
+
+        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertEquals("+14155551212", sms.getServiceCenterAddress());
+        assertTrue(sms.isEmail());
+        assertEquals("foo@example.com", sms.getEmailFrom());
+        assertEquals("foo@example.com", sms.getDisplayOriginatingAddress());
+        assertEquals("test subject", sms.getPseudoSubject());
+        assertEquals("test body", sms.getDisplayMessageBody());
+        assertEquals("test body", sms.getEmailBody());
+
+        // email gateway sms test, including gsm extended character set.
+        pdu = "07914151551512f204038105f400007011103105458a29e6f71b50c687db" +
+                "7076d9357eb741af0d0a442fcfe9c23739bfe16d289bdee6b5f1813629";
+
+        sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertEquals("+14155551212", sms.getServiceCenterAddress());
+        assertTrue(sms.isEmail());
+        assertEquals("foo@example.com", sms.getDisplayOriginatingAddress());
+        assertEquals("foo@example.com", sms.getEmailFrom());
+        assertEquals("{ testBody[^~\\] }", sms.getDisplayMessageBody());
+        assertEquals("{ testBody[^~\\] }", sms.getEmailBody());
+    }
+
+    @SmallTest
+    public void testExtendedCharacterTable() throws Exception {
+        String pdu = "07914151551512f2040B916105551511f100006080615131728A44D4F29C0E2" +
+                "AE3E96537B94C068DD16179784C2FCB41F4B0985D06B958ADD00FB0E94536AF9749" +
+                "74DA6D281BA00E95E26D509B946FC3DBF87A25D56A04";
+
+        SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+        assertEquals("+14155551212", sms.getServiceCenterAddress());
+        assertEquals("+16505551111", sms.getOriginatingAddress());
+        assertEquals("Test extended character table .,-!?@~_\\/&\"';^|:()<{}>[]=%*+#", sms.getMessageBody());
+    }
+
+    @SmallTest
+    public void testDecode() throws Exception {
+        byte[] septets = new byte[(7 * 128 + 7) / 8];
+
+        int bitOffset = 0;
+
+        for (int i = 0; i < 128; i++) {
+            int v;
+            if (i == 0x1b) {
+                // extended escape char
+                v = 0;
+            } else {
+                v = i;
+            }
+
+            int byteOffset = bitOffset / 8;
+            int shift = bitOffset % 8;
+
+            septets[byteOffset] |= v << shift;
+
+            if (shift > 1) {
+                septets[byteOffset + 1] = (byte) (v >> (8 - shift));
+            }
+
+            bitOffset += 7;
+        }
+
+        String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, 128);
+        byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded);
+
+        // reEncoded has the count septets byte at the front
+        assertEquals(reEncoded.length, septets.length + 1);
+
+        for (int i = 0; i < septets.length; i++) {
+            assertEquals(reEncoded[i + 1], septets[i]);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java b/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java
new file mode 100644
index 0000000..5d7349f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java
@@ -0,0 +1,54 @@
+package com.android.unit_tests;
+
+import com.google.android.net.SSLClientSessionCacheFactory;
+import com.android.internal.net.DbSSLSessionCache;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+/**
+ *  Unit test for {@link SSLClientSessionCacheFactory}.
+ */
+@MediumTest
+public final class SSLClientSessionCacheFactoryTest extends AndroidTestCase {
+
+    protected void tearDown() throws Exception {
+        setSslSessionCacheValue(getContext(), "");
+        super.tearDown();
+    }
+
+    private static void setSslSessionCacheValue(Context context, String value) {
+        ContentResolver resolver = context.getContentResolver();
+        Settings.Gservices.putString(resolver, Settings.Gservices.SSL_SESSION_CACHE, value);
+    }
+
+    private static SSLClientSessionCache getCache(Context context, String type) {
+        setSslSessionCacheValue(context, type);
+        return SSLClientSessionCacheFactory.getCache(context);
+    }
+
+    public void testGetDbCache() throws Exception {
+        Context context = getContext();
+        SSLClientSessionCache cache = getCache(context, "db");
+        assertNotNull(cache);
+        assertTrue(cache instanceof DbSSLSessionCache);
+    }
+
+    public void testGetFileCache() throws Exception {
+        Context context = getContext();
+        SSLClientSessionCache cache = getCache(context, "file");
+        assertNotNull(cache);
+        // yuck =)
+        assertEquals("org.apache.harmony.xnet.provider.jsse.FileClientSessionCache$Impl",
+                cache.getClass().getName());
+    }
+
+    public void testGetNoCache() throws Exception {
+        Context context = getContext();
+        SSLClientSessionCache cache = getCache(context, "none");
+        assertNull(cache);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java b/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java
new file mode 100644
index 0000000..9481180
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.net.SSLCertificateSocketFactory;
+import android.test.suitebuilder.annotation.Suppress;
+import junit.framework.TestCase;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+//This test relies on network resources.
+@Suppress
+public class SSLTest extends TestCase {
+    public void testCertificate() throws Exception {
+        // test www.fortify.net/sslcheck.html
+        Socket ssl = SSLCertificateSocketFactory.getDefault().createSocket("www.fortify.net",443);
+        assertNotNull(ssl);
+
+        OutputStream out = ssl.getOutputStream();
+        assertNotNull(out);
+
+        InputStream in = ssl.getInputStream();
+        assertNotNull(in);
+
+        String get = "GET /sslcheck.html HTTP/1.1\r\nHost: 68.178.217.222\r\n\r\n";
+
+        // System.out.println("going for write...");
+        out.write(get.getBytes());
+
+        byte[] b = new byte[1024];
+        // System.out.println("going for read...");
+        int ret = in.read(b);
+
+        // System.out.println(new String(b));
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java b/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java
new file mode 100644
index 0000000..d488a29
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.graphics.Bitmap;
+import android.sax.Element;
+import android.sax.ElementListener;
+import android.sax.EndTextElementListener;
+import android.sax.RootElement;
+import android.sax.StartElementListener;
+import android.sax.TextElementListener;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.format.Time;
+import android.util.Log;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class SafeSaxTest extends AndroidTestCase {
+
+    private static final String TAG = SafeSaxTest.class.getName();
+
+    private static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";
+    private static final String MEDIA_NAMESPACE = "http://search.yahoo.com/mrss/";
+    private static final String YOUTUBE_NAMESPACE = "http://gdata.youtube.com/schemas/2007";
+    private static final String GDATA_NAMESPACE = "http://schemas.google.com/g/2005";
+
+    private static class ElementCounter implements ElementListener {
+        int starts = 0;
+        int ends = 0;
+
+        public void start(Attributes attributes) {
+            starts++;
+        }
+
+        public void end() {
+            ends++;
+        }
+    }
+
+    private static class TextElementCounter implements TextElementListener {
+        int starts = 0;
+        String bodies = "";
+
+        public void start(Attributes attributes) {
+            starts++;
+        }
+
+        public void end(String body) {
+            this.bodies += body;
+        }
+    }
+
+    @SmallTest
+    public void testListener() throws Exception {
+        String xml = "<feed xmlns='http://www.w3.org/2005/Atom'>\n"
+                + "<entry>\n"
+                + "<id>a</id>\n"
+                + "</entry>\n"
+                + "<entry>\n"
+                + "<id>b</id>\n"
+                + "</entry>\n"
+                + "</feed>\n";
+
+        RootElement root = new RootElement(ATOM_NAMESPACE, "feed");
+        Element entry = root.requireChild(ATOM_NAMESPACE, "entry");
+        Element id = entry.requireChild(ATOM_NAMESPACE, "id");
+
+        ElementCounter rootCounter = new ElementCounter();
+        ElementCounter entryCounter = new ElementCounter();
+        TextElementCounter idCounter = new TextElementCounter();
+
+        root.setElementListener(rootCounter);
+        entry.setElementListener(entryCounter);
+        id.setTextElementListener(idCounter);
+
+        Xml.parse(xml, root.getContentHandler());
+
+        assertEquals(1, rootCounter.starts);
+        assertEquals(1, rootCounter.ends);
+        assertEquals(2, entryCounter.starts);
+        assertEquals(2, entryCounter.ends);
+        assertEquals(2, idCounter.starts);
+        assertEquals("ab", idCounter.bodies);
+    }
+
+    @SmallTest
+    public void testMissingRequiredChild() throws Exception {
+        String xml = "<feed></feed>";
+        RootElement root = new RootElement("feed");
+        root.requireChild("entry");
+
+        try {
+            Xml.parse(xml, root.getContentHandler());
+            fail("expected exception not thrown");
+        } catch (SAXException e) {
+            // Expected.
+        }
+    }
+
+    @SmallTest
+    public void testMixedContent() throws Exception {
+        String xml = "<feed><entry></entry></feed>";
+
+        RootElement root = new RootElement("feed");
+        root.setEndTextElementListener(new EndTextElementListener() {
+            public void end(String body) {
+            }
+        });
+
+        try {
+            Xml.parse(xml, root.getContentHandler());
+            fail("expected exception not thrown");
+        } catch (SAXException e) {
+            // Expected.
+        }
+    }
+
+    @LargeTest
+    public void testPerformance() throws Exception {
+        InputStream in = mContext.getResources().openRawResource(R.raw.youtube);
+        byte[] xmlBytes;
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream();
+            byte[] buffer = new byte[1024];
+            int length;
+            while ((length = in.read(buffer)) != -1) {
+                out.write(buffer, 0, length);
+            }
+            xmlBytes = out.toByteArray();
+        } finally {
+            in.close();
+        }
+
+        Log.i("***", "File size: " + (xmlBytes.length / 1024) + "k");
+
+        VideoAdapter videoAdapter = new VideoAdapter();
+        ContentHandler handler = newContentHandler(videoAdapter);
+        for (int i = 0; i < 2; i++) {
+            pureSaxTest(new ByteArrayInputStream(xmlBytes));
+            saxyModelTest(new ByteArrayInputStream(xmlBytes));
+            saxyModelTest(new ByteArrayInputStream(xmlBytes), handler);
+        }
+    }
+
+    private static void pureSaxTest(InputStream inputStream) throws IOException, SAXException {
+        long start = System.currentTimeMillis();
+        VideoAdapter videoAdapter = new VideoAdapter();
+        Xml.parse(inputStream, Xml.Encoding.UTF_8, new YouTubeContentHandler(videoAdapter));
+        long elapsed = System.currentTimeMillis() - start;
+        Log.i(TAG, "pure SAX: " + elapsed + "ms");
+    }
+
+    private static void saxyModelTest(InputStream inputStream) throws IOException, SAXException {
+        long start = System.currentTimeMillis();
+        VideoAdapter videoAdapter = new VideoAdapter();
+        Xml.parse(inputStream, Xml.Encoding.UTF_8, newContentHandler(videoAdapter));
+        long elapsed = System.currentTimeMillis() - start;
+        Log.i(TAG, "Saxy Model: " + elapsed + "ms");
+    }
+
+    private static void saxyModelTest(InputStream inputStream, ContentHandler contentHandler)
+            throws IOException, SAXException {
+        long start = System.currentTimeMillis();
+        Xml.parse(inputStream, Xml.Encoding.UTF_8, contentHandler);
+        long elapsed = System.currentTimeMillis() - start;
+        Log.i(TAG, "Saxy Model (preloaded): " + elapsed + "ms");
+    }
+
+    private static class VideoAdapter {
+        public void addVideo(YouTubeVideo video) {
+        }
+    }
+
+    private static ContentHandler newContentHandler(VideoAdapter videoAdapter) {
+        return new HandlerFactory().newContentHandler(videoAdapter);
+    }
+
+    private static class HandlerFactory {
+        YouTubeVideo video;
+
+        public ContentHandler newContentHandler(VideoAdapter videoAdapter) {
+            RootElement root = new RootElement(ATOM_NAMESPACE, "feed");
+
+            final VideoListener videoListener = new VideoListener(videoAdapter);
+
+            Element entry = root.getChild(ATOM_NAMESPACE, "entry");
+
+            entry.setElementListener(videoListener);
+
+            entry.getChild(ATOM_NAMESPACE, "id")
+                    .setEndTextElementListener(new EndTextElementListener() {
+                        public void end(String body) {
+                            video.videoId = body;
+                        }
+                    });
+
+            entry.getChild(ATOM_NAMESPACE, "published")
+                    .setEndTextElementListener(new EndTextElementListener() {
+                        public void end(String body) {
+                            // TODO(tomtaylor): programmatically get the timezone
+                            video.dateAdded = new Time(Time.TIMEZONE_UTC);
+                            video.dateAdded.parse3339(body);
+                        }
+                    });
+
+            Element author = entry.getChild(ATOM_NAMESPACE, "author");
+            author.getChild(ATOM_NAMESPACE, "name")
+                    .setEndTextElementListener(new EndTextElementListener() {
+                        public void end(String body) {
+                            video.authorName = body;
+                        }
+                    });
+
+            Element mediaGroup = entry.getChild(MEDIA_NAMESPACE, "group");
+
+            mediaGroup.getChild(MEDIA_NAMESPACE, "thumbnail")
+                    .setStartElementListener(new StartElementListener() {
+                        public void start(Attributes attributes) {
+                            String url = attributes.getValue("", "url");
+                            if (video.thumbnailUrl == null && url.length() > 0) {
+                                video.thumbnailUrl = url;
+                            }
+                        }
+                    });
+
+            mediaGroup.getChild(MEDIA_NAMESPACE, "content")
+                    .setStartElementListener(new StartElementListener() {
+                        public void start(Attributes attributes) {
+                            String url = attributes.getValue("", "url");
+                            if (url != null) {
+                                video.videoUrl = url;
+                            }
+                        }
+                    });
+
+            mediaGroup.getChild(MEDIA_NAMESPACE, "player")
+                    .setStartElementListener(new StartElementListener() {
+                        public void start(Attributes attributes) {
+                            String url = attributes.getValue("", "url");
+                            if (url != null) {
+                                video.playbackUrl = url;
+                            }
+                        }
+                    });
+
+            mediaGroup.getChild(MEDIA_NAMESPACE, "title")
+                    .setEndTextElementListener(new EndTextElementListener() {
+                        public void end(String body) {
+                            video.title = body;
+                        }
+                    });
+
+            mediaGroup.getChild(MEDIA_NAMESPACE, "category")
+                    .setEndTextElementListener(new EndTextElementListener() {
+                        public void end(String body) {
+                            video.category = body;
+                        }
+                    });
+
+            mediaGroup.getChild(MEDIA_NAMESPACE, "description")
+                    .setEndTextElementListener(new EndTextElementListener() {
+                        public void end(String body) {
+                            video.description = body;
+                        }
+                    });
+
+            mediaGroup.getChild(MEDIA_NAMESPACE, "keywords")
+                    .setEndTextElementListener(new EndTextElementListener() {
+                        public void end(String body) {
+                            video.tags = body;
+                        }
+                    });
+
+            mediaGroup.getChild(YOUTUBE_NAMESPACE, "duration")
+                    .setStartElementListener(new StartElementListener() {
+                        public void start(Attributes attributes) {
+                            String seconds = attributes.getValue("", "seconds");
+                            video.lengthInSeconds
+                                    = XmlUtils.convertValueToInt(seconds, 0);
+                        }
+                    });
+
+            mediaGroup.getChild(YOUTUBE_NAMESPACE, "statistics")
+                    .setStartElementListener(new StartElementListener() {
+                        public void start(Attributes attributes) {
+                            String viewCount = attributes.getValue("", "viewCount");
+                            video.viewCount
+                                    = XmlUtils.convertValueToInt(viewCount, 0);
+                        }
+                    });
+
+            entry.getChild(GDATA_NAMESPACE, "rating")
+                    .setStartElementListener(new StartElementListener() {
+                        public void start(Attributes attributes) {
+                            String average = attributes.getValue("", "average");
+                            video.rating = average == null
+                                    ? 0.0f : Float.parseFloat(average);
+                        }
+                    });
+
+            return root.getContentHandler();
+        }
+
+        class VideoListener implements ElementListener {
+
+            final VideoAdapter videoAdapter;
+
+            public VideoListener(VideoAdapter videoAdapter) {
+                this.videoAdapter = videoAdapter;
+            }
+
+            public void start(Attributes attributes) {
+                video = new YouTubeVideo();
+            }
+
+            public void end() {
+                videoAdapter.addVideo(video);
+                video = null;
+            }
+        }
+    }
+
+    private static class YouTubeContentHandler extends DefaultHandler {
+
+        final VideoAdapter videoAdapter;
+
+        YouTubeVideo video = null;
+        StringBuilder builder = null;
+
+        public YouTubeContentHandler(VideoAdapter videoAdapter) {
+            this.videoAdapter = videoAdapter;
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName,
+                Attributes attributes) throws SAXException {
+            if (uri.equals(ATOM_NAMESPACE)) {
+                if (localName.equals("entry")) {
+                    video = new YouTubeVideo();
+                    return;
+                }
+
+                if (video == null) {
+                    return;
+                }
+
+                if (!localName.equals("id")
+                        && !localName.equals("published")
+                        && !localName.equals("name")) {
+                    return;
+                }
+                this.builder = new StringBuilder();
+                return;
+
+            }
+
+            if (video == null) {
+                return;
+            }
+
+            if (uri.equals(MEDIA_NAMESPACE)) {
+                if (localName.equals("thumbnail")) {
+                    String url = attributes.getValue("", "url");
+                    if (video.thumbnailUrl == null && url.length() > 0) {
+                        video.thumbnailUrl = url;
+                    }
+                    return;
+                }
+
+                if (localName.equals("content")) {
+                    String url = attributes.getValue("", "url");
+                    if (url != null) {
+                        video.videoUrl = url;
+                    }
+                    return;
+                }
+
+                if (localName.equals("player")) {
+                    String url = attributes.getValue("", "url");
+                    if (url != null) {
+                        video.playbackUrl = url;
+                    }
+                    return;
+                }
+
+                if (localName.equals("title")
+                        || localName.equals("category")
+                        || localName.equals("description")
+                        || localName.equals("keywords")) {
+                    this.builder = new StringBuilder();
+                    return;
+                }
+
+                return;
+            }
+
+            if (uri.equals(YOUTUBE_NAMESPACE)) {
+                if (localName.equals("duration")) {
+                    video.lengthInSeconds = XmlUtils.convertValueToInt(
+                            attributes.getValue("", "seconds"), 0);
+                    return;
+                }
+
+                if (localName.equals("statistics")) {
+                    video.viewCount = XmlUtils.convertValueToInt(
+                            attributes.getValue("", "viewCount"), 0);
+                    return;
+                }
+
+                return;
+            }
+
+            if (uri.equals(GDATA_NAMESPACE)) {
+                if (localName.equals("rating")) {
+                    String average = attributes.getValue("", "average");
+                    video.rating = average == null
+                            ? 0.0f : Float.parseFloat(average);
+                }
+            }
+        }
+
+        @Override
+        public void characters(char text[], int start, int length)
+                throws SAXException {
+            if (builder != null) {
+                builder.append(text, start, length);
+            }
+        }
+
+        String takeText() {
+            try {
+                return builder.toString();
+            } finally {
+                builder = null;
+            }
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName)
+                throws SAXException {
+            if (video == null) {
+                return;
+            }
+
+            if (uri.equals(ATOM_NAMESPACE)) {
+                if (localName.equals("published")) {
+                    // TODO(tomtaylor): programmatically get the timezone
+                    video.dateAdded = new Time(Time.TIMEZONE_UTC);
+                    video.dateAdded.parse3339(takeText());
+                    return;
+                }
+
+                if (localName.equals("name")) {
+                    video.authorName = takeText();
+                    return;
+                }
+
+                if (localName.equals("id")) {
+                    video.videoId = takeText();
+                    return;
+                }
+
+                if (localName.equals("entry")) {
+                    // Add the video!
+                    videoAdapter.addVideo(video);
+                    video = null;
+                    return;
+                }
+
+                return;
+            }
+
+            if (uri.equals(MEDIA_NAMESPACE)) {
+                if (localName.equals("description")) {
+                    video.description = takeText();
+                    return;
+                }
+
+                if (localName.equals("keywords")) {
+                    video.tags = takeText();
+                    return;
+                }
+
+                if (localName.equals("category")) {
+                    video.category = takeText();
+                    return;
+                }
+
+                if (localName.equals("title")) {
+                    video.title = takeText();
+                }
+            }
+        }
+    }
+
+    private static class YouTubeVideo {
+        public String videoId;     // the id used to lookup on YouTube
+        public String videoUrl;       // the url to play the video
+        public String playbackUrl;    // the url to share for users to play video
+        public String thumbnailUrl;   // the url of the thumbnail image
+        public String title;
+        public Bitmap bitmap;      // cached bitmap of the thumbnail
+        public int lengthInSeconds;
+        public int viewCount;      // number of times the video has been viewed
+        public float rating;       // ranges from 0.0 to 5.0
+        public Boolean triedToLoadThumbnail;
+        public String authorName;
+        public Time dateAdded;
+        public String category;
+        public String tags;
+        public String description;
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
new file mode 100644
index 0000000..09e3b02
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.android.unit_tests.activity.LocalActivity;
+
+import android.app.Activity;
+import android.app.ISearchManager;
+import android.app.SearchManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.ServiceManager;
+import android.server.search.SearchableInfo;
+import android.server.search.SearchableInfo.ActionKeyInfo;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.MoreAsserts;
+import android.test.mock.MockContext;
+import android.test.mock.MockPackageManager;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.AndroidRuntimeException;
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * To launch this test from the command line:
+ * 
+ * adb shell am instrument -w \
+ *   -e class com.android.unit_tests.SearchManagerTest \
+ *   com.android.unit_tests/android.test.InstrumentationTestRunner
+ */
+public class SearchManagerTest extends ActivityInstrumentationTestCase<LocalActivity> {
+    
+    // If non-zero, enable a set of tests that start and stop the search manager.
+    // This is currently disabled because it's causing an unwanted jump from the unit test
+    // activity into the contacts activity.  We'll put this back after we disable that jump.
+    private static final int TEST_SEARCH_START = 0;
+    
+    /*
+     * Bug list of test ideas.
+     * 
+     * testSearchManagerInterfaceAvailable()
+     *  Exercise the interface obtained
+     *  
+     * testSearchManagerAvailable()
+     *  Exercise the interface obtained
+     *  
+     * testSearchManagerInvocations()
+     *  FIX - make it work again
+     *  stress test with a very long string
+     *  
+     * SearchableInfo tests
+     *  Mock the context so I can provide very specific input data
+     *  Confirm OK with "zero" searchables
+     *  Confirm "good" metadata read properly
+     *  Confirm "bad" metadata skipped properly
+     *  Confirm ordering of searchables
+     *  Confirm "good" actionkeys
+     *  confirm "bad" actionkeys are rejected
+     *  confirm XML ordering enforced (will fail today - bug in SearchableInfo)
+     *  findActionKey works
+     *  getIcon works
+     * 
+     * SearchManager tests
+     *  confirm proper identification of "default" activity based on policy, not hardcoded contacts
+     *  
+     * SearchBar tests
+     *  Maybe have to do with framework / unittest runner - need instrumented activity?
+     *  How can we unit test the suggestions content providers?
+     *  Should I write unit tests for any of them?
+     *  Test scenarios:
+     *    type-BACK (cancel)
+     *    type-GO (send)
+     *    type-navigate-click (suggestion)
+     *    type-action
+     *    type-navigate-action (suggestion)
+     */
+    
+    /**
+     * Local copy of activity context
+     */
+    Context mContext;
+
+    public SearchManagerTest() {
+        super("com.android.unit_tests", LocalActivity.class);
+    }
+
+    /**
+     * Setup any common data for the upcoming tests.
+     */
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        Activity testActivity = getActivity();
+        mContext = (Context)testActivity;
+    }
+
+    /**
+     * The goal of this test is to confirm that we can obtain
+     * a search manager interface.
+     */
+    @MediumTest
+    public void testSearchManagerInterfaceAvailable() {
+        ISearchManager searchManager1 = ISearchManager.Stub.asInterface(
+                ServiceManager.getService(Context.SEARCH_SERVICE));
+        assertNotNull(searchManager1);
+    }
+    
+    /**
+     * The goal of this test is to confirm that we can *only* obtain a search manager
+     * interface from an Activity context.
+     */
+    @MediumTest
+    public void testSearchManagerContextRestrictions() {
+        SearchManager searchManager1 = (SearchManager)
+                mContext.getSystemService(Context.SEARCH_SERVICE);
+        assertNotNull(searchManager1);
+        
+        Context applicationContext = mContext.getApplicationContext();
+        // this should fail, because you can't get a SearchManager from a non-Activity context
+        try {
+            applicationContext.getSystemService(Context.SEARCH_SERVICE);
+            assertFalse("Shouldn't retrieve SearchManager from a non-Activity context", true);
+        } catch (AndroidRuntimeException e) {
+            // happy here - we should catch this.
+        }
+    }
+    
+    /**
+     * The goal of this test is to confirm that we can obtain
+     * a search manager at any time, and that for any given context,
+     * it is a singleton.
+     */
+    @LargeTest
+    public void testSearchManagerAvailable() {
+        SearchManager searchManager1 = (SearchManager)
+                mContext.getSystemService(Context.SEARCH_SERVICE);
+        assertNotNull(searchManager1);
+        SearchManager searchManager2 = (SearchManager)
+                mContext.getSystemService(Context.SEARCH_SERVICE);
+        assertNotNull(searchManager2);
+        assertSame( searchManager1, searchManager2 );
+    }
+    
+    /**
+     * The goal of this test is to confirm that we can start and then
+     * stop a simple search.
+     */
+    
+   @MediumTest
+   public void testSearchManagerInvocations() {
+        SearchManager searchManager = (SearchManager)
+                mContext.getSystemService(Context.SEARCH_SERVICE);
+        assertNotNull(searchManager);
+        
+            // TODO: make a real component name, or remove this need
+        final ComponentName cn = new ComponentName("", "");
+
+        if (TEST_SEARCH_START != 0) {
+            // These tests should simply run to completion w/o exceptions
+            searchManager.startSearch(null, false, cn, null, false);
+            searchManager.stopSearch();
+            
+            searchManager.startSearch("", false, cn, null, false);
+            searchManager.stopSearch();
+            
+            searchManager.startSearch("test search string", false, cn, null, false);
+            searchManager.stopSearch();
+            
+            searchManager.startSearch("test search string", true, cn, null, false);
+            searchManager.stopSearch();
+        }
+     }
+    
+    /**
+     * The goal of this test is to confirm proper operation of the 
+     * SearchableInfo helper class.
+     * 
+     * TODO:  The metadata source needs to be mocked out because adding
+     * searchability metadata via this test is causing it to leak into the
+     * real system.  So for now I'm just going to test for existence of the
+     * GoogleSearch app (which is searchable).
+     */
+    @LargeTest
+    public void testSearchableGoogleSearch() {
+        // test basic array & hashmap
+        SearchableInfo.buildSearchableList(mContext);
+
+        // test linkage from another activity
+        // TODO inject this via mocking into the package manager.
+        // TODO for now, just check for searchable GoogleSearch app (this isn't really a unit test)
+        ComponentName thisActivity = new ComponentName(
+                "com.android.googlesearch", 
+                "com.android.googlesearch.GoogleSearch");
+
+        SearchableInfo si = SearchableInfo.getSearchableInfo(mContext, thisActivity);
+        assertNotNull(si);
+        assertTrue(si.mSearchable);
+        assertEquals(thisActivity, si.mSearchActivity);
+        
+        Context appContext = si.getActivityContext(mContext);
+        assertNotNull(appContext);
+        MoreAsserts.assertNotEqual(appContext, mContext);
+        assertEquals("Google Search", appContext.getString(si.getHintId()));
+        assertEquals("Google", appContext.getString(si.getLabelId()));
+    }
+    
+    /**
+     * Test that non-searchable activities return no searchable info (this would typically
+     * trigger the use of the default searchable e.g. contacts)
+     */
+    @LargeTest
+    public void testNonSearchable() {
+        // test basic array & hashmap
+        SearchableInfo.buildSearchableList(mContext);
+
+        // confirm that we return null for non-searchy activities
+        ComponentName nonActivity = new ComponentName(
+                            "com.android.unit_tests",
+                            "com.android.unit_tests.NO_SEARCH_ACTIVITY");
+        SearchableInfo si = SearchableInfo.getSearchableInfo(mContext, nonActivity);
+        assertNull(si);
+    }
+    
+    /**
+     * This is an attempt to run the searchable info list with a mocked context.  Here are some
+     * things I'd like to test.
+     *
+     *  Confirm OK with "zero" searchables
+     *  Confirm "good" metadata read properly
+     *  Confirm "bad" metadata skipped properly
+     *  Confirm ordering of searchables
+     *  Confirm "good" actionkeys
+     *  confirm "bad" actionkeys are rejected
+     *  confirm XML ordering enforced (will fail today - bug in SearchableInfo)
+     *  findActionKey works
+     *  getIcon works
+
+     */
+    @LargeTest
+    public void testSearchableMocked() {
+        MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager());
+        MyMockContext mockContext = new MyMockContext(mContext, mockPM);
+        ArrayList<SearchableInfo> searchables;
+        int count;
+
+        // build item list with real-world source data
+        mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_PASSTHROUGH);
+        SearchableInfo.buildSearchableList(mockContext);
+        // tests with "real" searchables (deprecate, this should be a unit test)
+        searchables = SearchableInfo.getSearchablesList();
+        count = searchables.size();
+        assertTrue(count >= 1);         // this isn't really a unit test
+        checkSearchables(searchables);
+
+        // build item list with mocked search data
+        // this round of tests confirms good operations with "zero" searchables found
+        // This should return either a null pointer or an empty list
+        mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_MOCK_ZERO);
+        SearchableInfo.buildSearchableList(mockContext);
+        searchables = SearchableInfo.getSearchablesList();
+        if (searchables != null) {
+            count = searchables.size();
+            assertTrue(count == 0);
+        }
+    }
+    
+    /**
+     * Generic health checker for an array of searchables.
+     * 
+     * This is designed to pass for any semi-legal searchable, without knowing much about
+     * the format of the underlying data.  It's fairly easy for a non-compliant application
+     * to provide meta-data that will pass here (e.g. a non-existent suggestions authority).
+     * 
+     * @param searchables The list of searchables to examine.
+     */
+    private void checkSearchables(ArrayList<SearchableInfo> searchablesList) {
+        assertNotNull(searchablesList);
+        int count = searchablesList.size();
+        for (int ii = 0; ii < count; ii++) {
+            SearchableInfo si = searchablesList.get(ii);
+            assertNotNull(si);
+            assertTrue(si.mSearchable);
+            assertTrue(si.getLabelId() != 0);        // This must be a useable string
+            assertNotEmpty(si.mSearchActivity.getClassName());
+            assertNotEmpty(si.mSearchActivity.getPackageName());
+            if (si.getSuggestAuthority() != null) {
+                // The suggestion fields are largely optional, so we'll just confirm basic health
+                assertNotEmpty(si.getSuggestAuthority());
+                assertNullOrNotEmpty(si.getSuggestPath());
+                assertNullOrNotEmpty(si.getSuggestSelection());
+                assertNullOrNotEmpty(si.getSuggestIntentAction());
+                assertNullOrNotEmpty(si.getSuggestIntentData());
+            }
+            /* Add a way to get the entire action key list, then explicitly test its elements */
+            /* For now, test the most common action key (CALL) */
+            ActionKeyInfo ai = si.findActionKey(KeyEvent.KEYCODE_CALL);
+            if (ai != null) {
+                assertEquals(ai.mKeyCode, KeyEvent.KEYCODE_CALL);
+                // one of these three fields must be non-null & non-empty
+                boolean m1 = (ai.mQueryActionMsg != null) && (ai.mQueryActionMsg.length() > 0);
+                boolean m2 = (ai.mSuggestActionMsg != null) && (ai.mSuggestActionMsg.length() > 0);
+                boolean m3 = (ai.mSuggestActionMsgColumn != null) && 
+                                (ai.mSuggestActionMsgColumn.length() > 0);
+                assertTrue(m1 || m2 || m3);
+            }
+            
+            /* 
+             * Find ways to test these:
+             * 
+             * private int mSearchMode
+             * private Drawable mIcon
+             */
+            
+            /*
+             * Explicitly not tested here:
+             * 
+             * Can be null, so not much to see:
+             * public String mSearchHint
+             * private String mZeroQueryBanner
+             * 
+             * To be deprecated/removed, so don't bother:
+             * public boolean mFilterMode
+             * public boolean mQuickStart
+             * private boolean mIconResized
+             * private int mIconResizeWidth
+             * private int mIconResizeHeight
+             * 
+             * All of these are "internal" working variables, not part of any contract
+             * private ActivityInfo mActivityInfo
+             * private Rect mTempRect
+             * private String mSuggestProviderPackage
+             * private String mCacheActivityContext
+             */
+        }
+    }
+    
+    /**
+     * Combo assert for "string not null and not empty"
+     */
+    private void assertNotEmpty(final String s) {
+        assertNotNull(s);
+        MoreAsserts.assertNotEqual(s, "");
+    }
+    
+    /**
+     * Combo assert for "string null or (not null and not empty)"
+     */
+    private void assertNullOrNotEmpty(final String s) {
+        if (s != null) {
+            MoreAsserts.assertNotEqual(s, "");
+        }
+    }    
+    
+    /**
+     * This is a mock for context.  Used to perform a true unit test on SearchableInfo.
+     * 
+     */
+    private class MyMockContext extends MockContext {
+        
+        protected Context mRealContext;
+        protected PackageManager mPackageManager;
+        
+        /**
+         * Constructor.
+         * 
+         * @param realContext Please pass in a real context for some pass-throughs to function.
+         */
+        MyMockContext(Context realContext, PackageManager packageManager) {
+            mRealContext = realContext;
+            mPackageManager = packageManager;
+        }
+        
+        /**
+         * Resources.  Pass through for now.
+         */
+        @Override
+        public Resources getResources() {
+            return mRealContext.getResources();
+        }
+
+        /**
+         * Package manager.  Pass through for now.
+         */
+        @Override
+        public PackageManager getPackageManager() {
+            return mPackageManager;
+        }
+
+        /**
+         * Package manager.  Pass through for now.
+         */
+        @Override
+        public Context createPackageContext(String packageName, int flags)
+                throws PackageManager.NameNotFoundException {
+            return mRealContext.createPackageContext(packageName, flags);
+        }
+    }
+
+/**
+ * This is a mock for package manager.  Used to perform a true unit test on SearchableInfo.
+ * 
+ */
+    private class MyMockPackageManager extends MockPackageManager {
+        
+        public final static int SEARCHABLES_PASSTHROUGH = 0;
+        public final static int SEARCHABLES_MOCK_ZERO = 1;
+        public final static int SEARCHABLES_MOCK_ONEGOOD = 2;
+        public final static int SEARCHABLES_MOCK_ONEGOOD_ONEBAD = 3;
+        
+        protected PackageManager mRealPackageManager;
+        protected int mSearchablesMode;
+
+        public MyMockPackageManager(PackageManager realPM) {
+            mRealPackageManager = realPM;
+            mSearchablesMode = SEARCHABLES_PASSTHROUGH;
+        }
+
+        /**
+         * Set the mode for various tests.
+         */
+        public void setSearchablesMode(int newMode) {
+            switch (newMode) {
+            case SEARCHABLES_PASSTHROUGH:
+            case SEARCHABLES_MOCK_ZERO:
+                mSearchablesMode = newMode;
+                break;
+                
+            default:
+                throw new UnsupportedOperationException();       
+            }
+        }
+        
+        /**
+         * Find activities that support a given intent.
+         * 
+         * Retrieve all activities that can be performed for the given intent.
+         * 
+         * @param intent The desired intent as per resolveActivity().
+         * @param flags Additional option flags.  The most important is
+         *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
+         *                    those activities that support the CATEGORY_DEFAULT.
+         * 
+         * @return A List<ResolveInfo> containing one entry for each matching
+         *         Activity. These are ordered from best to worst match -- that
+         *         is, the first item in the list is what is returned by
+         *         resolveActivity().  If there are no matching activities, an empty
+         *         list is returned.
+         */
+        @Override 
+        public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
+            assertNotNull(intent);
+            assertEquals(intent.getAction(), Intent.ACTION_SEARCH);
+            switch (mSearchablesMode) {
+            case SEARCHABLES_PASSTHROUGH:
+                return mRealPackageManager.queryIntentActivities(intent, flags);
+            case SEARCHABLES_MOCK_ZERO:
+                return null;
+            default:
+                throw new UnsupportedOperationException();
+            }
+        }
+        
+        /**
+         * Retrieve an XML file from a package.  This is a low-level API used to
+         * retrieve XML meta data.
+         * 
+         * @param packageName The name of the package that this xml is coming from.
+         * Can not be null.
+         * @param resid The resource identifier of the desired xml.  Can not be 0.
+         * @param appInfo Overall information about <var>packageName</var>.  This
+         * may be null, in which case the application information will be retrieved
+         * for you if needed; if you already have this information around, it can
+         * be much more efficient to supply it here.
+         * 
+         * @return Returns an XmlPullParser allowing you to parse out the XML
+         * data.  Returns null if the xml resource could not be found for any
+         * reason.
+         */
+        @Override 
+        public XmlResourceParser getXml(String packageName, int resid, ApplicationInfo appInfo) {
+            assertNotNull(packageName);
+            MoreAsserts.assertNotEqual(packageName, "");
+            MoreAsserts.assertNotEqual(resid, 0);
+            switch (mSearchablesMode) {
+            case SEARCHABLES_PASSTHROUGH:
+                return mRealPackageManager.getXml(packageName, resid, appInfo);
+            case SEARCHABLES_MOCK_ZERO:
+            default:
+                throw new UnsupportedOperationException();
+            }
+        }
+        
+        /**
+         * Find a single content provider by its base path name.
+         * 
+         * @param name The name of the provider to find.
+         * @param flags Additional option flags.  Currently should always be 0.
+         * 
+         * @return ContentProviderInfo Information about the provider, if found,
+         *         else null.
+         */
+        @Override 
+        public ProviderInfo resolveContentProvider(String name, int flags) {
+            assertNotNull(name);
+            MoreAsserts.assertNotEqual(name, "");
+            assertEquals(flags, 0);
+            switch (mSearchablesMode) {
+            case SEARCHABLES_PASSTHROUGH:
+                return mRealPackageManager.resolveContentProvider(name, flags);
+            case SEARCHABLES_MOCK_ZERO:
+            default:
+                throw new UnsupportedOperationException();
+            }
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java b/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java
new file mode 100644
index 0000000..4b64144
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests serialization of user-level classes.
+ */
+public class SerializationTest extends TestCase {
+
+    static class MySerializable implements Serializable {}
+
+    @SmallTest
+    public void testSerialization() throws IOException, ClassNotFoundException {
+        ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        ObjectOutputStream oout = new ObjectOutputStream(bout);
+        oout.writeObject(new MySerializable());
+        oout.close();
+
+        ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+        Object o = new ObjectInputStream(bin).readObject();
+        assertTrue(o instanceof MySerializable);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java b/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java
new file mode 100644
index 0000000..8b1db97
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/** Unit test for SettingsProvider. */
+public class SettingsProviderTest extends AndroidTestCase {
+    @MediumTest
+    public void testNameValueCache() {
+        ContentResolver r = getContext().getContentResolver();
+        Settings.Gservices.putString(r, "test_service", "Value");
+        assertEquals("Value", Settings.Gservices.getString(r, "test_service"));
+
+        // Make sure the value can be overwritten.
+        Settings.Gservices.putString(r, "test_service", "New");
+        assertEquals("New", Settings.Gservices.getString(r, "test_service"));
+
+        // Also that delete works.
+        assertEquals(1, r.delete(Settings.Gservices.getUriFor("test_service"), null, null));
+        assertEquals(null, Settings.Gservices.getString(r, "test_service"));
+
+        // Try all the same things in the System table
+        Settings.System.putString(r, "test_setting", "Value");
+        assertEquals("Value", Settings.System.getString(r, "test_setting"));
+
+        Settings.System.putString(r, "test_setting", "New");
+        assertEquals("New", Settings.System.getString(r, "test_setting"));
+
+        assertEquals(1, r.delete(Settings.System.getUriFor("test_setting"), null, null));
+        assertEquals(null, Settings.System.getString(r, "test_setting"));
+    }
+
+    @MediumTest
+    public void testRowNameContentUri() {
+        ContentResolver r = getContext().getContentResolver();
+
+        assertEquals("content://settings/system/test_setting",
+                Settings.System.getUriFor("test_setting").toString());
+        assertEquals("content://settings/gservices/test_service",
+                Settings.Gservices.getUriFor("test_service").toString());
+
+        // These tables use the row name (not ID) as their content URI.
+        Uri tables[] = { Settings.System.CONTENT_URI, Settings.Gservices.CONTENT_URI };
+        for (Uri table : tables) {
+            ContentValues v = new ContentValues();
+            v.put(Settings.System.NAME, "test_key");
+            v.put(Settings.System.VALUE, "Test");
+            Uri uri = r.insert(table, v);
+            assertEquals(table.toString() + "/test_key", uri.toString());
+
+            // Query with a specific URI and no WHERE clause succeeds.
+            Cursor c = r.query(uri, null, null, null, null);
+            try {
+                assertTrue(c.moveToNext());
+                assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
+                assertEquals("Test", c.getString(c.getColumnIndex(Settings.System.VALUE)));
+                assertFalse(c.moveToNext());
+            } finally {
+                c.close();
+            }
+
+            // Query with a specific URI and a WHERE clause fails.
+            try {
+                r.query(uri, null, "1", null, null);
+                fail("UnsupportedOperationException expected");
+            } catch (UnsupportedOperationException e) {
+                if (!e.toString().contains("WHERE clause")) throw e;
+            }
+
+            // Query with a tablewide URI and a WHERE clause succeeds.
+            c = r.query(table, null, "name='test_key'", null, null);
+            try {
+                assertTrue(c.moveToNext());
+                assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
+                assertEquals("Test", c.getString(c.getColumnIndex(Settings.System.VALUE)));
+                assertFalse(c.moveToNext());
+            } finally {
+                c.close();
+            }
+
+            v = new ContentValues();
+            v.put(Settings.System.VALUE, "Toast");
+            assertEquals(1, r.update(uri, v, null, null));
+
+            c = r.query(uri, null, null, null, null);
+            try {
+                assertTrue(c.moveToNext());
+                assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
+                assertEquals("Toast", c.getString(c.getColumnIndex(Settings.System.VALUE)));
+                assertFalse(c.moveToNext());
+            } finally {
+                c.close();
+            }
+
+            assertEquals(1, r.delete(uri, null, null));
+        }
+
+        assertEquals(null, Settings.System.getString(r, "test_key"));
+        assertEquals(null, Settings.Gservices.getString(r, "test_key"));
+    }
+
+    @MediumTest
+    public void testRowNumberContentUri() {
+        ContentResolver r = getContext().getContentResolver();
+
+        // The bookmarks table (and everything else) uses standard row number content URIs.
+        Uri uri = Settings.Bookmarks.add(r, new Intent("TEST"),
+                "Test Title", "Test Folder", '*', 123);
+
+        assertTrue(ContentUris.parseId(uri) > 0);
+
+        assertEquals("TEST", Settings.Bookmarks.getIntentForShortcut(r, '*').getAction());
+
+        ContentValues v = new ContentValues();
+        v.put(Settings.Bookmarks.INTENT, "#Intent;action=TOAST;end");
+        assertEquals(1, r.update(uri, v, null, null));
+
+        assertEquals("TOAST", Settings.Bookmarks.getIntentForShortcut(r, '*').getAction());
+
+        assertEquals(1, r.delete(uri, null, null));
+
+        assertEquals(null, Settings.Bookmarks.getIntentForShortcut(r, '*'));
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java b/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java
new file mode 100644
index 0000000..9758298
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import com.google.android.util.SimplePullParser;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class SimplePullParserTest extends TestCase {
+    @SmallTest
+    public void testTwoLevels() throws Exception {
+        String xml = ""
+                + "<top a='1' b='hello'>\n"
+                + "  <next c='2' d='there'/>\n"
+                + "  <next c='3' d='bye'/>\n"
+                + "</top>";
+        SimplePullParser parser = new SimplePullParser(xml);
+        int depth0 = parser.getDepth();
+        assertEquals(0, depth0);
+        assertEquals("top", parser.nextTag(depth0));
+        assertEquals(1, parser.getIntAttribute(null, "a"));
+        assertEquals("hello", parser.getStringAttribute(null, "b"));
+
+        int depth1 = parser.getDepth();
+        assertEquals(1, depth1);
+        assertEquals("next", parser.nextTag(depth1));
+        assertEquals(2, parser.getIntAttribute(null, "c"));
+        assertEquals("there", parser.getStringAttribute(null, "d"));
+        assertEquals("next", parser.nextTag(depth1));
+        assertEquals(3, parser.getIntAttribute(null, "c"));
+        assertEquals("bye", parser.getStringAttribute(null, "d"));
+        assertNull(parser.nextTag(depth1));
+
+        assertNull(parser.nextTag(depth0));
+    }
+
+    @SmallTest
+    public void testAttributes() throws Exception {
+        String xml = "<top a='1' b='hello'/>";
+        SimplePullParser parser = new SimplePullParser(xml);
+        int depth = parser.getDepth();
+        parser.nextTag(depth);
+
+        assertEquals(2, parser.numAttributes());
+        assertEquals("a", parser.getAttributeName(0));
+        assertEquals("b", parser.getAttributeName(1));
+
+        assertEquals(1, parser.getIntAttribute(null, "a"));
+        assertEquals(5, parser.getIntAttribute(null, "c", 5));
+        assertEquals("hello", parser.getStringAttribute(null, "b"));
+        assertEquals("not", parser.getStringAttribute(null, "d", "not"));
+    }
+
+    @SmallTest
+    public void testRecovery() throws Exception {
+        String xml = ""
+                + "<top a='1' b='hello'>\n"
+                + "  <middle c='2' d='there'>\n"
+                + "    <inner/>\n"
+                + "    <inner2/>\n"
+                + "    <inner3/>\n"
+                + "  </middle>\n"
+                + "  <middle2/>\n"
+                + "</top>";
+        SimplePullParser parser = new SimplePullParser(xml);
+        assertEquals(0, parser.getDepth());
+        assertEquals("top", parser.nextTag(0));
+        assertEquals(1, parser.getDepth());
+        assertEquals("middle", parser.nextTag(1));
+        assertEquals(2, parser.getDepth());
+        assertEquals("inner", parser.nextTag(2));
+        // Now skip some elements.
+        assertEquals("middle2", parser.nextTag(1));
+    }
+
+    @SmallTest
+    public void testCdata() throws Exception {
+        StringBuilder cdataBuilder;
+        String xml = ""
+                + "<top>"
+                + "<![CDATA[data0]]>"
+                + "<next0/>"
+                + "<![CDATA[data1]]>"
+                + "<next1/>"
+                + "<![CDATA[data2]]>"
+                + "<next2/>"
+                + "<![CDATA[data3]]>"
+                + "<next3/>"
+                + "<![CDATA[data4]]>"
+                + "<next4/>"
+                + "<![CDATA[data5]]>"
+                + "</top>";
+        SimplePullParser parser = new SimplePullParser(xml);
+        assertEquals("top", parser.nextTag(0));
+
+        // We can ignore cdata by not passing a cdata builder.
+        assertEquals("next0", parser.nextTag(1));
+
+        // We can get the most recent cdata by passing an empty cdata builder.
+        cdataBuilder = new StringBuilder();
+        assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder));
+        assertEquals("data1", cdataBuilder.toString());
+        assertEquals("next1", parser.nextTag(1));
+
+        // We can join multiple cdatas by reusing a builder.
+        cdataBuilder = new StringBuilder();
+        assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder));
+        assertEquals("next2", parser.nextTag(1));
+        assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder));
+        assertEquals("data2data3", cdataBuilder.toString());
+        assertEquals("next3", parser.nextTag(1));
+
+        // We can read all of the remaining cdata while ignoring any elements.
+        cdataBuilder = new StringBuilder();
+        parser.readRemainingText(1, cdataBuilder);
+        assertEquals("data4data5", cdataBuilder.toString());
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java b/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java
new file mode 100644
index 0000000..0e2f0c5
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.Telephony.Sms;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.util.GregorianCalendar;
+
+public class SmsProviderTest extends AndroidTestCase {
+
+    @LargeTest
+    public void testProvider() throws Exception {
+        // This test does the following
+        //  1. Insert 10 messages from the same number at different times.
+        //
+        //  . Delete the messages and make sure that they were deleted.
+
+        long now = System.currentTimeMillis();
+
+        Uri[] urls = new Uri[10];
+        String[] dates = new String[]{
+                Long.toString(new GregorianCalendar(1970, 1, 1, 0, 0, 0).getTimeInMillis()),
+                Long.toString(new GregorianCalendar(1971, 2, 13, 16, 35, 3).getTimeInMillis()),
+                Long.toString(new GregorianCalendar(1978, 10, 22, 0, 1, 0).getTimeInMillis()),
+                Long.toString(new GregorianCalendar(1980, 1, 11, 10, 22, 30).getTimeInMillis()),
+                Long.toString(now - (5 * 24 * 60 * 60 * 1000)),
+                Long.toString(now - (2 * 24 * 60 * 60 * 1000)),
+                Long.toString(now - (5 * 60 * 60 * 1000)),
+                Long.toString(now - (30 * 60 * 1000)),
+                Long.toString(now - (5 * 60 * 1000)),
+                Long.toString(now)
+        };
+
+        ContentValues map = new ContentValues();
+        map.put("address", "+15045551337");
+        map.put("read", 0);
+
+        ContentResolver contentResolver = mContext.getContentResolver();
+
+        for (int i = 0; i < urls.length; i++) {
+            map.put("body", "Test " + i + " !");
+            map.put("date", dates[i]);
+            urls[i] = contentResolver.insert(Sms.Inbox.CONTENT_URI, map);
+            assertNotNull(urls[i]);
+        }
+
+        Cursor c = contentResolver.query(Sms.Inbox.CONTENT_URI, null, null, null, "date");
+
+        //DatabaseUtils.dumpCursor(c);
+
+        for (Uri url : urls) {
+            int count = contentResolver.delete(url, null, null);
+            assertEquals(1, count);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java b/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java
new file mode 100644
index 0000000..9e3f483
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.graphics.Typeface;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.*;
+import android.text.style.*;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+/**
+ * SpannedTest tests some features of Spanned
+ */
+public class SpannedTest extends TestCase {
+    private int mExpect;
+
+    @SmallTest
+    public void testSpannableString() throws Exception {
+        checkPriority(new SpannableString("the quick brown fox"));
+    }
+
+    @SmallTest
+    public void testSpannableStringBuilder() throws Exception {
+        checkPriority2(new SpannableStringBuilder("the quick brown fox"));
+    }
+
+    @SmallTest
+    public void testAppend() throws Exception {
+        Object o = new Object();
+        SpannableString ss = new SpannableString("Test");
+        ss.setSpan(o, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        SpannableStringBuilder ssb = new SpannableStringBuilder();
+        ssb.append(ss);
+        assertEquals(0, ssb.getSpanStart(o));
+        assertEquals(4, ssb.getSpanEnd(o));
+        assertEquals(1, ssb.getSpans(0, 4, Object.class).length);
+
+        ssb.insert(0, ss);
+        assertEquals(4, ssb.getSpanStart(o));
+        assertEquals(8, ssb.getSpanEnd(o));
+        assertEquals(0, ssb.getSpans(0, 4, Object.class).length);
+        assertEquals(1, ssb.getSpans(4, 8, Object.class).length);
+    }
+
+    @SmallTest
+    public void testWrapParcel() {
+        SpannableString s = new SpannableString("Hello there world");
+        CharacterStyle mark = new StyleSpan(Typeface.BOLD);
+        s.setSpan(mark, 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        s.setSpan(CharacterStyle.wrap(mark), 3, 7,
+                  Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        s.setSpan(new TextAppearanceSpan("mono", 0, -1, null, null), 7, 8,
+                  Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        s.setSpan(CharacterStyle.wrap(new TypefaceSpan("mono")), 8, 9,
+                  Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        Parcel p = Parcel.obtain();
+        TextUtils.writeToParcel(s, p, 0);
+        p.setDataPosition(0);
+
+        Spanned s2 = (Spanned) TextUtils.CHAR_SEQUENCE_CREATOR.
+                        createFromParcel(p);
+        StyleSpan[] style;
+
+        style = s2.getSpans(1, 2, StyleSpan.class);
+        assertEquals(1, style.length);
+        assertEquals(1, s2.getSpanStart(style[0]));
+        assertEquals(2, s2.getSpanEnd(style[0]));
+
+        style = s2.getSpans(3, 7, StyleSpan.class);
+        assertEquals(1, style.length);
+        assertEquals(3, s2.getSpanStart(style[0]));
+        assertEquals(7, s2.getSpanEnd(style[0]));
+
+        TextAppearanceSpan[] appearance = s2.getSpans(7, 8,
+                                                TextAppearanceSpan.class);
+        assertEquals(1, appearance.length);
+        assertEquals(7, s2.getSpanStart(appearance[0]));
+        assertEquals(8, s2.getSpanEnd(appearance[0]));
+
+        TypefaceSpan[] tf = s2.getSpans(8, 9, TypefaceSpan.class);
+        assertEquals(1, tf.length);
+        assertEquals(8, s2.getSpanStart(tf[0]));
+        assertEquals(9, s2.getSpanEnd(tf[0]));
+    }
+
+    private void checkPriority(Spannable s) {
+        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+                                      (5 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+                                      (10 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+                                      (0 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+                                      (15 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+                                      (3 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+                                      (6 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+                                      (0 << Spannable.SPAN_PRIORITY_SHIFT));
+
+        Object[] spans = s.getSpans(0, s.length(), Object.class);
+
+        for (int i = 0; i < spans.length - 1; i++) {
+            assertEquals((s.getSpanFlags(spans[i]) & Spanned.SPAN_PRIORITY) >=
+                         (s.getSpanFlags(spans[i + 1]) & Spanned.SPAN_PRIORITY),
+                         true);
+        }
+
+        mExpect = 0;
+
+        s.setSpan(new Watcher(2), 0, s.length(), 
+                  Spannable.SPAN_INCLUSIVE_INCLUSIVE |
+                  (2 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Watcher(4), 0, s.length(), 
+                  Spannable.SPAN_INCLUSIVE_INCLUSIVE |
+                  (4 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Watcher(1), 0, s.length(), 
+                  Spannable.SPAN_INCLUSIVE_INCLUSIVE |
+                  (1 << Spannable.SPAN_PRIORITY_SHIFT));
+        s.setSpan(new Watcher(3), 0, s.length(), 
+                  Spannable.SPAN_INCLUSIVE_INCLUSIVE |
+                  (3 << Spannable.SPAN_PRIORITY_SHIFT));
+
+        mExpect = 4;
+        s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        assertEquals(mExpect, 0);
+    }
+
+    private void checkPriority2(SpannableStringBuilder ssb) {
+        checkPriority(ssb);
+
+        mExpect = 4;
+        ssb.insert(3, "something");
+        assertEquals(mExpect, 0);
+    }
+
+    private class Watcher implements SpanWatcher, TextWatcher {
+        private int mSequence;
+
+        public Watcher(int sequence) {
+            mSequence = sequence;
+        }
+
+        public void onSpanChanged(Spannable b, Object o, int s, int e,
+                                  int st, int en) { }
+        public void onSpanRemoved(Spannable b, Object o, int s, int e) { }
+
+        public void onSpanAdded(Spannable b, Object o, int s, int e) {
+            if (mExpect != 0) {
+                assertEquals(mSequence, mExpect);
+                mExpect = mSequence - 1;
+            }
+        }
+
+        public void beforeTextChanged(CharSequence s, int start, int count,
+                                      int after) { }
+        public void onTextChanged(CharSequence s, int start, int before,
+                                      int count) {
+            if (mExpect != 0) {
+                assertEquals(mSequence, mExpect);
+                mExpect = mSequence - 1;
+            }
+        }
+
+        public void afterTextChanged(Editable s) { }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/StringTest.java b/tests/AndroidTests/src/com/android/unit_tests/StringTest.java
new file mode 100644
index 0000000..dc40a0a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/StringTest.java
@@ -0,0 +1,951 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import java.util.Locale;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+public class StringTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    public static final String STATIC_STRING_01 = "Hello Android";
+    public static final String STATIC_STRING_02 =
+            "Remember, today is the tomorrow you worried about yesterday";
+    public static final char[] STATIC_CHAR_ARRAY =
+            {'N', 'A', 'N', 'D', 'R', 'O', 'I', 'D'};
+    public static StringBuffer STATIC_SBUF = new StringBuffer(STATIC_STRING_02);
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    /** Create an empty String object* */
+
+    public void testStringCreate() {
+        String rString;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = new String();
+            rString = new String();
+            rString = new String();
+            rString = new String();
+            rString = new String();
+            rString = new String();
+            rString = new String();
+            rString = new String();
+            rString = new String();
+            rString = new String();
+        }
+    }
+
+    /** Create an initialised String object* */
+
+    public void testStringCreate1() {
+        String rString, str = STATIC_STRING_01;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = new String(str);
+            rString = new String(str);
+            rString = new String(str);
+            rString = new String(str);
+            rString = new String(str);
+            rString = new String(str);
+            rString = new String(str);
+            rString = new String(str);
+            rString = new String(str);
+            rString = new String(str); // 10
+        }
+    }
+
+    /** equals() with for loop* */
+    public void testStringEquals() {
+        String mString = new String(STATIC_STRING_01);
+        String str = STATIC_STRING_01;
+        boolean result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = mString.equals(str);
+            result = mString.equals(str);
+            result = mString.equals(str);
+            result = mString.equals(str);
+            result = mString.equals(str);
+            result = mString.equals(str);
+            result = mString.equals(str);
+            result = mString.equals(str);
+            result = mString.equals(str);
+            result = mString.equals(str);
+        }
+    }
+
+    /**
+     * ContentEquals- Comparing the content of a String with that of a String
+     * Buffer*
+     */
+
+    public void testStringContentEquals() {
+        StringBuffer sBuf = new StringBuffer(STATIC_STRING_01);
+        String str = STATIC_STRING_01;
+        boolean result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+            result = str.contentEquals(sBuf);
+        }
+    }
+
+    /** Compare string objects lexicographically using compareTo() with for loop* */
+
+    public void testStringCompareTo() {
+        String str1 = new String(STATIC_STRING_01);
+        String str2 = STATIC_STRING_01;
+        int result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+            result = str1.compareTo(str2);
+        }
+
+    }
+
+    /** Compare string objects using compareToIgnorecase() with for loop* */
+
+    public void testStringCompareToIgnoreCase() {
+        String mString = new String(STATIC_STRING_01);
+        String str2 = STATIC_STRING_01;
+        int result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+            result = mString.compareToIgnoreCase(str2);
+        }
+    }
+
+    /** startsWith * */
+
+    public void testStringstartsWith() {
+        boolean result;
+        String str1 = STATIC_STRING_02, str2 = "Rem";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+            result = str1.startsWith(str2);
+        }
+    }
+
+    /** startsWith(String seq, int begin) * */
+
+    public void testStringstartsWith1() {
+        String str1 = STATIC_STRING_02, str2 = "tom";
+        int pos = 10;
+        boolean result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+            result = str1.startsWith(str2, pos);
+        }
+    }
+
+    /** endsWith * */
+
+    public void testStringendsWith() {
+        String str = STATIC_STRING_02, str1 = "day";
+        boolean result;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+            result = str.endsWith(str1);
+        }
+    }
+
+    /**
+     * indexOf to determine whether a string contains a substring
+     */
+    public void testStringindexOf() {
+        boolean result;
+        String str = STATIC_STRING_02, str1 = "tomo";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+            result = str.indexOf(str1) > 0;
+        }
+    }
+
+    /** indexOf()* */
+
+    public void testStringindexOf1() {
+        int index;
+        String str = STATIC_STRING_02;
+        char c = 't';
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+            index = str.indexOf(c);
+        }
+
+    }
+
+    /** indexOf(char c, int start)* */
+    public void testStringindexOf2() {
+        int index, pos = 12;
+        String str = STATIC_STRING_02, str1 = "tom";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+            index = str.indexOf(str1, pos);
+        }
+    }
+
+    /** lastIndexOf()* */
+
+    public void testStringlastIndexOf() {
+        int index;
+        char c = 't';
+        String str = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+            index = str.lastIndexOf(c);
+        }
+    }
+
+    /** lastIndexOf()* */
+
+    public void testStringlastIndexOf1() {
+        int index, pos = 36;
+        String str = STATIC_STRING_02, str1 = "tom";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+            index = str.lastIndexOf(str1, pos);
+        }
+    }
+
+    /**
+     * contains() to determine whether a string contains a substring
+     */
+
+    public void testStringcontains() {
+        boolean result;
+        String str = STATIC_STRING_02, str1 = "tomo";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            result = str.contains(str1);
+            result = str.contains(str1);
+            result = str.contains(str1);
+            result = str.contains(str1);
+            result = str.contains(str1);
+            result = str.contains(str1);
+            result = str.contains(str1);
+            result = str.contains(str1);
+            result = str.contains(str1);
+            result = str.contains(str1);
+        }
+    }
+
+    /** substring(int start) */
+
+    public void testStringsubstring() {
+        String rString;
+        String str = STATIC_STRING_02;
+        int index = 10;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = str.substring(index);
+            rString = str.substring(index);
+            rString = str.substring(index);
+            rString = str.substring(index);
+            rString = str.substring(index);
+            rString = str.substring(index);
+            rString = str.substring(index);
+            rString = str.substring(index);
+            rString = str.substring(index);
+            rString = str.substring(index);
+        }
+    }
+
+    /** substring(int start, int end) in a for loop* */
+
+    public void testStringsubstring1() {
+        String rString;
+        String str = STATIC_STRING_02;
+        int start = 10, end = 48;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+            rString = str.substring(start, end);
+        }
+    }
+
+    /**
+     * valueOf(char[] cArray) String representation of a character array
+     */
+    public void testStringvalueOf() {
+        String rString;
+        char[] cArray = STATIC_CHAR_ARRAY;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+            rString = String.valueOf(cArray);
+        }
+    }
+
+    /** valueOf(char[] cArray, int offset, int count)* */
+
+    public void testStringvalueOf1() {
+        String rString;
+        char[] cArray = STATIC_CHAR_ARRAY;
+        int start = 1, end = 7;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+            rString = String.valueOf(cArray, start, end);
+        }
+    }
+
+    /** Convert a string to a char Array* */
+
+    public void testStringtoCharArray() {
+        char[] cArray;
+        String str = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+            cArray = str.toCharArray();
+        }
+    }
+
+    /** length()* */
+
+    public void testStringlength() {
+        int len;
+        String str = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            len = str.length();
+            len = str.length();
+            len = str.length();
+            len = str.length();
+            len = str.length();
+            len = str.length();
+            len = str.length();
+            len = str.length();
+            len = str.length();
+            len = str.length();
+        }
+    }
+
+    /** hashcode()* */
+
+    public void testStringhashCode() {
+        int index;
+        String str = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = str.hashCode();
+            index = str.hashCode();
+            index = str.hashCode();
+            index = str.hashCode();
+            index = str.hashCode();
+            index = str.hashCode();
+            index = str.hashCode();
+            index = str.hashCode();
+            index = str.hashCode();
+            index = str.hashCode();
+        }
+    }
+
+    /** replace()* */
+
+    public void testStringreplace() {
+        String rString;
+        String str = STATIC_STRING_02;
+        char c1 = ' ', c2 = ' ';
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+            rString = str.replace(c1, c2);
+        }
+    }
+
+    public void testStringreplaceAll() {
+        String rString;
+        String str = STATIC_STRING_02, str1 = " ", str2 = "/";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+            rString = str.replaceAll(str1, str2);
+        }
+    }
+
+    /** Convert a StringBuffer to a String* */
+
+    public void testStringtoString() {
+        StringBuffer sBuf = new StringBuffer(STATIC_STRING_02);
+
+        String rString;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+            rString = sBuf.toString();
+        }
+    }
+
+    /** Split a string into an array of strings* */
+
+    public void testStringsplit() {
+        String[] strings;
+        String str1 = STATIC_STRING_02, str = " ";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            strings = str1.split(str);
+            strings = str1.split(str);
+            strings = str1.split(str);
+            strings = str1.split(str);
+            strings = str1.split(str);
+            strings = str1.split(str);
+            strings = str1.split(str);
+            strings = str1.split(str);
+            strings = str1.split(str);
+            strings = str1.split(str);
+
+        }
+    }
+
+    /** Split a string into an array of strings* */
+
+    public void testStringsplit1() {
+        String str = STATIC_STRING_02, str1 = " ";
+        String[] strings;
+        int pos = 8;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+            strings = str.split(str1, pos);
+        }
+    }
+
+    public void testStringgetBytes() {
+        byte[] bytes;
+        String str = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+            bytes = str.getBytes();
+        }
+    }
+
+    /** copyValueOf(char[] data) * */
+
+    public void testStringcopyValueOf() {
+        String rString;
+        char[] cArray = STATIC_CHAR_ARRAY;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+            rString = String.copyValueOf(cArray);
+        }
+    }
+
+    /** copyValueOf(char[] data, int index, int count)* */
+
+    public void testStringcopyValueOf1() {
+        String rString;
+        int start = 1, end = 7;
+        char[] cArray = STATIC_CHAR_ARRAY;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+            rString = String.copyValueOf(cArray, start, end);
+        }
+    }
+
+    /** trim()* */
+
+    public void testStringtrim() {
+        String mString =
+                new String(
+                        "                            HELLO ANDROID                                                ");
+        String rString;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = mString.trim();
+            rString = mString.trim();
+            rString = mString.trim();
+            rString = mString.trim();
+            rString = mString.trim();
+            rString = mString.trim();
+            rString = mString.trim();
+            rString = mString.trim();
+            rString = mString.trim();
+            rString = mString.trim();
+        }
+    }
+
+    /** getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)* */
+
+    public void testStringgetChars() {
+        char[] cArray = STATIC_CHAR_ARRAY;
+        String str = STATIC_STRING_01;
+        int value1 = 7, value2 = 12, value3 = 1;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+            str.getChars(value1, value2, cArray, value3);
+        }
+    }
+
+    /** toUpperCase()* */
+
+    public void testStringtoUpperCase() {
+        String rString, str = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+            rString = str.toUpperCase();
+        }
+    }
+
+    /** toUpperCase() with locale* */
+
+    public void testStringtoUpperCase1() {
+        Locale locale = new Locale("tr");
+        String str = STATIC_STRING_02;
+        String rString;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+            rString = str.toUpperCase(locale);
+        }
+    }
+
+    /** toLowerCase* */
+
+    public void StringtoLowerCase() {
+        String rString, str = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+            rString = str.toLowerCase();
+        }
+    }
+
+    /** toLowerCase with locale* */
+
+    public void testStringtoLowerCase1() {
+        Locale locale = new Locale("tr");
+        String rString, str = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+            rString = str.toLowerCase(locale);
+        }
+    }
+
+    /** charAt()* */
+
+    public void testStringcharAt() {
+        String str = STATIC_STRING_02;
+        int index, pos = 21;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+            index = str.charAt(pos);
+        }
+    }
+
+    public void testStringConcat() {
+        String mString, str1 = STATIC_STRING_01, str2 = STATIC_STRING_02;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+            mString = str1.concat(str2);
+        }
+    }
+
+    public void testStringBufferAppend() {
+        StringBuffer sBuf = new StringBuffer(" ");
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            sBuf.append(i);
+            sBuf.append(i);
+            sBuf.append(i);
+            sBuf.append(i);
+            sBuf.append(i);
+            sBuf.append(i);
+            sBuf.append(i);
+            sBuf.append(i);
+            sBuf.append(i);
+            sBuf.append(i);
+        }
+    }
+
+    public void testStringBufferInsert() {
+        StringBuffer sBuf = new StringBuffer(" ");
+        int index = sBuf.length();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+            sBuf.insert(index, i);
+        }
+    }
+
+    public void testStringBufferReverse() {
+        StringBuffer sBuf = STATIC_SBUF;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            sBuf.reverse();
+            sBuf.reverse();
+            sBuf.reverse();
+            sBuf.reverse();
+            sBuf.reverse();
+            sBuf.reverse();
+            sBuf.reverse();
+            sBuf.reverse();
+            sBuf.reverse();
+            sBuf.reverse();
+        }
+    }
+
+    public void testStringBufferSubstring() {
+        StringBuffer sBuf = STATIC_SBUF;
+        String rString;
+        int index = 0;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+            rString = sBuf.substring(index);
+        }
+    }
+
+    public void testStringBufferSubstring1() {
+        StringBuffer sBuf = STATIC_SBUF;
+        String rString;
+        int start = 5, end = 25;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+            rString = sBuf.substring(start, end);
+        }
+    }
+
+    public void testStringBufferReplace() {
+        StringBuffer sBuf = STATIC_SBUF;
+        int start = 3, end = 6;
+        String str = "ind";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+            sBuf.replace(start, end, str);
+        }
+    }
+
+    public void testStringBufferIndexOf() {
+        StringBuffer sBuf = STATIC_SBUF;
+        String str = "t";
+        int index;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+            index = sBuf.indexOf(str);
+        }
+    }
+
+    public void testStringBufferIndexOf1() {
+        StringBuffer sBuf = STATIC_SBUF;
+        String str = "tom";
+        int index, pos = 12;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+            index = sBuf.indexOf(str, pos);
+        }
+
+    }
+
+    public void testStringBufferLastIndexOf() {
+        StringBuffer sBuf = STATIC_SBUF;
+        String str = "t";
+        int index;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+            index = sBuf.lastIndexOf(str);
+        }
+    }
+
+    public void testStringBufferLastIndexOf1() {
+        StringBuffer sBuf = STATIC_SBUF;
+        int index, pos = 36;
+        String str = "tom";
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+            index = sBuf.lastIndexOf(str, pos);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java
new file mode 100644
index 0000000..9b5e655
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java
@@ -0,0 +1,116 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/mockup/TestHttpClient.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package com.android.unit_tests;
+
+import java.io.IOException;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpClientConnection;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.DefaultedHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.http.protocol.RequestConnControl;
+import org.apache.http.protocol.RequestContent;
+import org.apache.http.protocol.RequestExpectContinue;
+import org.apache.http.protocol.RequestTargetHost;
+import org.apache.http.protocol.RequestUserAgent;
+
+public class TestHttpClient {
+
+    private final HttpParams params;
+    private final BasicHttpProcessor httpproc;
+    private final HttpRequestExecutor httpexecutor;
+    private final ConnectionReuseStrategy connStrategy;
+    private final HttpContext context;
+    
+    public TestHttpClient() {
+        super();
+        this.params = new BasicHttpParams();
+        this.params
+            .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
+            .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
+            .setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1)
+            .setParameter(CoreProtocolPNames.USER_AGENT, "TEST-CLIENT/1.1");
+
+        this.httpproc = new BasicHttpProcessor();
+        // Required protocol interceptors
+        this.httpproc.addInterceptor(new RequestContent());
+        this.httpproc.addInterceptor(new RequestTargetHost());
+        // Recommended protocol interceptors
+        this.httpproc.addInterceptor(new RequestConnControl());
+        this.httpproc.addInterceptor(new RequestUserAgent());
+        this.httpproc.addInterceptor(new RequestExpectContinue());
+
+        this.httpexecutor = new HttpRequestExecutor();
+        this.connStrategy = new DefaultConnectionReuseStrategy();
+        this.context = new BasicHttpContext(null);
+    }
+
+    public HttpParams getParams() {
+        return this.params;
+    }
+    
+    public HttpResponse execute(
+            final HttpRequest request,
+            final HttpHost targetHost,
+            final HttpClientConnection conn) throws HttpException, IOException {
+        this.context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
+        this.context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, targetHost);
+        this.context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
+        request.setParams(
+                    new DefaultedHttpParams(request.getParams(), this.params));
+        this.httpexecutor.preProcess(request, this.httpproc, this.context);
+        HttpResponse response = this.httpexecutor.execute(request, conn, this.context);
+        response.setParams(
+                new DefaultedHttpParams(response.getParams(), this.params));
+        this.httpexecutor.postProcess(response, this.httpproc, this.context);
+        return response;
+    }
+    
+    public boolean keepAlive(final HttpResponse response) {
+        return this.connStrategy.keepAlive(response, this.context);
+    }
+    
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java
new file mode 100644
index 0000000..aae21b3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java
@@ -0,0 +1,207 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/mockup/TestHttpServer.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package com.android.unit_tests;
+
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import org.apache.http.ConnectionClosedException;
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.HttpServerConnection;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.DefaultHttpResponseFactory;
+import org.apache.http.impl.DefaultHttpServerConnection;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpExpectationVerifier;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.HttpRequestHandlerRegistry;
+import org.apache.http.protocol.HttpService;
+import org.apache.http.protocol.ResponseConnControl;
+import org.apache.http.protocol.ResponseContent;
+import org.apache.http.protocol.ResponseDate;
+import org.apache.http.protocol.ResponseServer;
+
+public class TestHttpServer {
+
+    private final HttpParams params; 
+    private final BasicHttpProcessor httpproc;
+    private final ConnectionReuseStrategy connStrategy;
+    private final HttpResponseFactory responseFactory;
+    private final HttpRequestHandlerRegistry reqistry;
+    private final ServerSocket serversocket;
+    
+    private HttpExpectationVerifier expectationVerifier;
+    
+    private Thread listener;
+    private volatile boolean shutdown;
+    
+    public TestHttpServer() throws IOException {
+        super();
+        this.params = new BasicHttpParams();
+        this.params
+            .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
+            .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
+            .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
+            .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
+            .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "TEST-SERVER/1.1");
+        this.httpproc = new BasicHttpProcessor();
+        this.httpproc.addInterceptor(new ResponseDate());
+        this.httpproc.addInterceptor(new ResponseServer());
+        this.httpproc.addInterceptor(new ResponseContent());
+        this.httpproc.addInterceptor(new ResponseConnControl());
+        this.connStrategy = new DefaultConnectionReuseStrategy();
+        this.responseFactory = new DefaultHttpResponseFactory();
+        this.reqistry = new HttpRequestHandlerRegistry();
+        this.serversocket = new ServerSocket(0);
+    }
+    
+    public void registerHandler(
+            final String pattern, 
+            final HttpRequestHandler handler) {
+        this.reqistry.register(pattern, handler);
+    }
+    
+    public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
+        this.expectationVerifier = expectationVerifier;
+    }
+    
+    private HttpServerConnection acceptConnection() throws IOException {
+        Socket socket = this.serversocket.accept();
+        DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
+        conn.bind(socket, this.params);
+        return conn;
+    }
+    
+    public int getPort() {
+        return this.serversocket.getLocalPort();
+    }
+    
+    public InetAddress getInetAddress() {
+        return this.serversocket.getInetAddress();
+    }
+    
+    public void start() {
+        if (this.listener != null) {
+            throw new IllegalStateException("Listener already running");
+        }
+        this.listener = new Thread(new Runnable() {
+           
+            public void run() {
+                while (!shutdown && !Thread.interrupted()) {
+                    try {
+                        // Set up HTTP connection
+                        HttpServerConnection conn = acceptConnection();
+                        // Set up the HTTP service
+                        HttpService httpService = new HttpService(
+                                httpproc, 
+                                connStrategy,
+                                responseFactory);
+                        httpService.setParams(params);
+                        httpService.setExpectationVerifier(expectationVerifier);
+                        httpService.setHandlerResolver(reqistry);
+                        
+                        // Start worker thread
+                        Thread t = new WorkerThread(httpService, conn);
+                        t.setDaemon(true);
+                        t.start();
+                    } catch (InterruptedIOException ex) {
+                        break;
+                    } catch (IOException e) {
+                        break;
+                    }
+                }
+            }
+            
+        });
+        this.listener.start();
+    }
+
+    public void shutdown() {
+        if (this.shutdown) {
+            return;
+        }
+        this.shutdown = true;
+        try {
+            this.serversocket.close();
+        } catch (IOException ignore) {}
+        this.listener.interrupt();
+        try {
+            this.listener.join(1000);
+        } catch (InterruptedException ignore) {}
+    }
+    
+    static class WorkerThread extends Thread {
+
+        private final HttpService httpservice;
+        private final HttpServerConnection conn;
+        
+        public WorkerThread(
+                final HttpService httpservice, 
+                final HttpServerConnection conn) {
+            super();
+            this.httpservice = httpservice;
+            this.conn = conn;
+        }
+        
+        public void run() {
+            HttpContext context = new BasicHttpContext(null);
+            try {
+                while (!Thread.interrupted() && this.conn.isOpen()) {
+                    this.httpservice.handleRequest(this.conn, context);
+                }
+            } catch (ConnectionClosedException ex) {
+            } catch (IOException ex) {
+                System.err.println("I/O error: " + ex.getMessage());
+            } catch (HttpException ex) {
+                System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
+            } finally {
+                try {
+                    this.conn.shutdown();
+                } catch (IOException ignore) {}
+            }
+        }
+
+    }
+    
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java
new file mode 100644
index 0000000..6b57d13
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java
@@ -0,0 +1,608 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/protocol/TestHttpServiceAndExecutor.java $
+ * $Revision: 576073 $
+ * $Date: 2007-09-16 03:53:13 -0700 (Sun, 16 Sep 2007) $
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package com.android.unit_tests;
+
+import org.apache.http.protocol.HttpExpectationVerifier;
+import org.apache.http.protocol.HttpRequestHandler;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import junit.framework.TestCase;
+
+import org.apache.http.Header;
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.DefaultHttpClientConnection;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EncodingUtils;
+import org.apache.http.util.EntityUtils;
+
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class TestHttpService extends TestCase implements PerformanceTestCase {
+
+    public boolean isPerformanceOnly() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    public int startPerformance(Intermediates intermediates) {
+        // TODO Auto-generated method stub
+        return 0;
+    }
+    
+    private TestHttpServer server;
+    private TestHttpClient client;
+    
+    protected void setUp() throws Exception {
+        this.server = new TestHttpServer();
+        this.client = new TestHttpClient();
+    }
+
+    protected void tearDown() throws Exception {
+        if (server != null) {
+          this.server.shutdown();
+        }
+    }    
+   
+    /**
+     * This test case executes a series of simple GET requests 
+     */
+    @LargeTest
+    public void testSimpleBasicHttpRequests() throws Exception {
+        
+        int reqNo = 20;
+        
+        Random rnd = new Random();
+        
+        // Prepare some random data
+        final List testData = new ArrayList(reqNo);
+        for (int i = 0; i < reqNo; i++) {
+            int size = rnd.nextInt(5000);
+            byte[] data = new byte[size];
+            rnd.nextBytes(data);
+            testData.add(data);
+        }
+
+        // Initialize the server-side request handler
+        this.server.registerHandler("*", new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                
+                String s = request.getRequestLine().getUri();
+                if (s.startsWith("/?")) {
+                    s = s.substring(2);
+                }
+                int index = Integer.parseInt(s);
+                byte[] data = (byte []) testData.get(index);
+                ByteArrayEntity entity = new ByteArrayEntity(data); 
+                response.setEntity(entity);
+            }
+            
+        });
+        
+        this.server.start();
+        
+        DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+        HttpHost host = new HttpHost("localhost", this.server.getPort());
+        
+        try {
+            for (int r = 0; r < reqNo; r++) {
+                if (!conn.isOpen()) {
+                    Socket socket = new Socket(host.getHostName(), host.getPort());
+                    conn.bind(socket, this.client.getParams());
+                }
+                
+                BasicHttpRequest get = new BasicHttpRequest("GET", "/?" + r);
+                HttpResponse response = this.client.execute(get, host, conn);
+                byte[] received = EntityUtils.toByteArray(response.getEntity());
+                byte[] expected = (byte[]) testData.get(r);
+                
+                assertEquals(expected.length, received.length);
+                for (int i = 0; i < expected.length; i++) {
+                    assertEquals(expected[i], received[i]);
+                }
+                if (!this.client.keepAlive(response)) {
+                    conn.close();
+                }
+            }
+            
+            //Verify the connection metrics
+            HttpConnectionMetrics cm = conn.getMetrics();
+            assertEquals(reqNo, cm.getRequestCount());
+            assertEquals(reqNo, cm.getResponseCount());
+            
+        } finally {
+            conn.close();
+            this.server.shutdown();
+        }
+    }
+
+    /**
+     * This test case executes a series of simple POST requests with content length 
+     * delimited content. 
+     */
+    @LargeTest
+    public void testSimpleHttpPostsWithContentLength() throws Exception {
+        
+        int reqNo = 20;
+        
+        Random rnd = new Random();
+        
+        // Prepare some random data
+        List testData = new ArrayList(reqNo);
+        for (int i = 0; i < reqNo; i++) {
+            int size = rnd.nextInt(5000);
+            byte[] data = new byte[size];
+            rnd.nextBytes(data);
+            testData.add(data);
+        }
+
+        // Initialize the server-side request handler
+        this.server.registerHandler("*", new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                
+                if (request instanceof HttpEntityEnclosingRequest) {
+                    HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
+                    byte[] data = EntityUtils.toByteArray(incoming);
+                    
+                    ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                    outgoing.setChunked(false);
+                    response.setEntity(outgoing);
+                } else {
+                    StringEntity outgoing = new StringEntity("No content"); 
+                    response.setEntity(outgoing);
+                }
+            }
+            
+        });
+        
+        this.server.start();
+        
+        DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+        HttpHost host = new HttpHost("localhost", this.server.getPort());
+        
+        try {
+            for (int r = 0; r < reqNo; r++) {
+                if (!conn.isOpen()) {
+                    Socket socket = new Socket(host.getHostName(), host.getPort());
+                    conn.bind(socket, this.client.getParams());
+                }
+                
+                BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+                byte[] data = (byte[]) testData.get(r);
+                ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                post.setEntity(outgoing);
+
+                HttpResponse response = this.client.execute(post, host, conn);
+                byte[] received = EntityUtils.toByteArray(response.getEntity());
+                byte[] expected = (byte[]) testData.get(r);
+                
+                assertEquals(expected.length, received.length);
+                for (int i = 0; i < expected.length; i++) {
+                    assertEquals(expected[i], received[i]);
+                }
+                if (!this.client.keepAlive(response)) {
+                    conn.close();
+                }
+            }
+            //Verify the connection metrics
+            HttpConnectionMetrics cm = conn.getMetrics();
+            assertEquals(reqNo, cm.getRequestCount());
+            assertEquals(reqNo, cm.getResponseCount());
+            
+        } finally {
+            conn.close();
+            this.server.shutdown();
+        }
+    }
+
+    /**
+     * This test case executes a series of simple POST requests with chunk 
+     * coded content content. 
+     */
+    @LargeTest
+    public void testSimpleHttpPostsChunked() throws Exception {
+        
+        int reqNo = 20;
+        
+        Random rnd = new Random();
+        
+        // Prepare some random data
+        List testData = new ArrayList(reqNo);
+        for (int i = 0; i < reqNo; i++) {
+            int size = rnd.nextInt(20000);
+            byte[] data = new byte[size];
+            rnd.nextBytes(data);
+            testData.add(data);
+        }
+
+        // Initialize the server-side request handler
+        this.server.registerHandler("*", new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                
+                if (request instanceof HttpEntityEnclosingRequest) {
+                    HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
+                    byte[] data = EntityUtils.toByteArray(incoming);
+                    
+                    ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                    outgoing.setChunked(true);
+                    response.setEntity(outgoing);
+                } else {
+                    StringEntity outgoing = new StringEntity("No content"); 
+                    response.setEntity(outgoing);
+                }
+            }
+            
+        });
+        
+        this.server.start();
+        
+        DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+        HttpHost host = new HttpHost("localhost", this.server.getPort());
+        
+        try {
+            for (int r = 0; r < reqNo; r++) {
+                if (!conn.isOpen()) {
+                    Socket socket = new Socket(host.getHostName(), host.getPort());
+                    conn.bind(socket, this.client.getParams());
+                }
+                
+                BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+                byte[] data = (byte[]) testData.get(r);
+                ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                outgoing.setChunked(true);
+                post.setEntity(outgoing);
+
+                HttpResponse response = this.client.execute(post, host, conn);
+                byte[] received = EntityUtils.toByteArray(response.getEntity());
+                byte[] expected = (byte[]) testData.get(r);
+                
+                assertEquals(expected.length, received.length);
+                for (int i = 0; i < expected.length; i++) {
+                    assertEquals(expected[i], received[i]);
+                }
+                if (!this.client.keepAlive(response)) {
+                    conn.close();
+                }
+            }
+            //Verify the connection metrics
+            HttpConnectionMetrics cm = conn.getMetrics();
+            assertEquals(reqNo, cm.getRequestCount());
+            assertEquals(reqNo, cm.getResponseCount());
+        } finally {
+            conn.close();
+            this.server.shutdown();
+        }
+    }
+
+    /**
+     * This test case executes a series of simple HTTP/1.0 POST requests. 
+     */
+    @LargeTest
+    public void testSimpleHttpPostsHTTP10() throws Exception {
+        
+        int reqNo = 20;
+        
+        Random rnd = new Random();
+        
+        // Prepare some random data
+        List testData = new ArrayList(reqNo);
+        for (int i = 0; i < reqNo; i++) {
+            int size = rnd.nextInt(5000);
+            byte[] data = new byte[size];
+            rnd.nextBytes(data);
+            testData.add(data);
+        }
+
+        // Initialize the server-side request handler
+        this.server.registerHandler("*", new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                
+                if (request instanceof HttpEntityEnclosingRequest) {
+                    HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
+                    byte[] data = EntityUtils.toByteArray(incoming);
+                    
+                    ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                    outgoing.setChunked(false);
+                    response.setEntity(outgoing);
+                } else {
+                    StringEntity outgoing = new StringEntity("No content"); 
+                    response.setEntity(outgoing);
+                }
+            }
+            
+        });
+        
+        this.server.start();
+        
+        // Set protocol level to HTTP/1.0
+        this.client.getParams().setParameter(
+                CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_0);
+        
+        DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+        HttpHost host = new HttpHost("localhost", this.server.getPort());
+        
+        try {
+            for (int r = 0; r < reqNo; r++) {
+                if (!conn.isOpen()) {
+                    Socket socket = new Socket(host.getHostName(), host.getPort());
+                    conn.bind(socket, this.client.getParams());
+                }
+                
+                BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+                byte[] data = (byte[]) testData.get(r);
+                ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                post.setEntity(outgoing);
+
+                HttpResponse response = this.client.execute(post, host, conn);
+                assertEquals(HttpVersion.HTTP_1_0, response.getStatusLine().getProtocolVersion());
+                byte[] received = EntityUtils.toByteArray(response.getEntity());
+                byte[] expected = (byte[]) testData.get(r);
+                
+                assertEquals(expected.length, received.length);
+                for (int i = 0; i < expected.length; i++) {
+                    assertEquals(expected[i], received[i]);
+                }
+                if (!this.client.keepAlive(response)) {
+                    conn.close();
+                }
+            }
+            
+            //Verify the connection metrics
+            HttpConnectionMetrics cm = conn.getMetrics();
+            assertEquals(reqNo, cm.getRequestCount());
+            assertEquals(reqNo, cm.getResponseCount());
+        } finally {
+            conn.close();
+            this.server.shutdown();
+        }
+    }
+
+    /**
+     * This test case executes a series of simple POST requests using 
+     * the 'expect: continue' handshake. 
+     */
+    @LargeTest
+    public void testHttpPostsWithExpectContinue() throws Exception {
+        
+        int reqNo = 20;
+        
+        Random rnd = new Random();
+        
+        // Prepare some random data
+        List testData = new ArrayList(reqNo);
+        for (int i = 0; i < reqNo; i++) {
+            int size = rnd.nextInt(5000);
+            byte[] data = new byte[size];
+            rnd.nextBytes(data);
+            testData.add(data);
+        }
+
+        // Initialize the server-side request handler
+        this.server.registerHandler("*", new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                
+                if (request instanceof HttpEntityEnclosingRequest) {
+                    HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
+                    byte[] data = EntityUtils.toByteArray(incoming);
+                    
+                    ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                    outgoing.setChunked(true);
+                    response.setEntity(outgoing);
+                } else {
+                    StringEntity outgoing = new StringEntity("No content"); 
+                    response.setEntity(outgoing);
+                }
+            }
+            
+        });
+        
+        this.server.start();
+        
+        // Activate 'expect: continue' handshake
+        this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
+        
+        DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+        HttpHost host = new HttpHost("localhost", this.server.getPort());
+        
+        try {
+            for (int r = 0; r < reqNo; r++) {
+                if (!conn.isOpen()) {
+                    Socket socket = new Socket(host.getHostName(), host.getPort());
+                    conn.bind(socket, this.client.getParams());
+                }
+                
+                BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+                byte[] data = (byte[]) testData.get(r);
+                ByteArrayEntity outgoing = new ByteArrayEntity(data);
+                outgoing.setChunked(true);
+                post.setEntity(outgoing);
+
+                HttpResponse response = this.client.execute(post, host, conn);
+                byte[] received = EntityUtils.toByteArray(response.getEntity());
+                byte[] expected = (byte[]) testData.get(r);
+                
+                assertEquals(expected.length, received.length);
+                for (int i = 0; i < expected.length; i++) {
+                    assertEquals(expected[i], received[i]);
+                }
+                if (!this.client.keepAlive(response)) {
+                    conn.close();
+                }
+            }
+            
+            //Verify the connection metrics
+            HttpConnectionMetrics cm = conn.getMetrics();
+            assertEquals(reqNo, cm.getRequestCount());
+            assertEquals(reqNo, cm.getResponseCount());
+        } finally {
+            conn.close();
+            this.server.shutdown();
+        }
+    }
+    
+    
+    /**
+     * This test case executes a series of simple POST requests that do not 
+     * meet the target server expectations. 
+     */
+    @LargeTest
+    public void testHttpPostsWithExpectationVerification() throws Exception {
+        
+        int reqNo = 3;
+        
+        // Initialize the server-side request handler
+        this.server.registerHandler("*", new HttpRequestHandler() {
+
+            public void handle(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException, IOException {
+                
+                StringEntity outgoing = new StringEntity("No content"); 
+                response.setEntity(outgoing);
+            }
+            
+        });
+        
+        this.server.setExpectationVerifier(new HttpExpectationVerifier() {
+
+            public void verify(
+                    final HttpRequest request, 
+                    final HttpResponse response, 
+                    final HttpContext context) throws HttpException {
+                Header someheader = request.getFirstHeader("Secret");
+                if (someheader != null) {
+                    int secretNumber;
+                    try {
+                        secretNumber = Integer.parseInt(someheader.getValue());
+                    } catch (NumberFormatException ex) {
+                        response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
+                        return;
+                    }
+                    if (secretNumber < 2) {
+                        response.setStatusCode(HttpStatus.SC_EXPECTATION_FAILED);
+                        ByteArrayEntity outgoing = new ByteArrayEntity(
+                                EncodingUtils.getAsciiBytes("Wrong secret number")); 
+                        response.setEntity(outgoing);
+                    }
+                }
+            }
+            
+        });
+        
+        this.server.start();
+        
+        // Activate 'expect: continue' handshake
+        this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
+        
+        DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+        HttpHost host = new HttpHost("localhost", this.server.getPort());
+        
+        try {
+            for (int r = 0; r < reqNo; r++) {
+                if (!conn.isOpen()) {
+                    Socket socket = new Socket(host.getHostName(), host.getPort());
+                    conn.bind(socket, this.client.getParams());
+                }
+                
+                BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+                post.addHeader("Secret", Integer.toString(r));
+                ByteArrayEntity outgoing = new ByteArrayEntity(
+                        EncodingUtils.getAsciiBytes("No content")); 
+                post.setEntity(outgoing);
+
+                HttpResponse response = this.client.execute(post, host, conn);
+
+                HttpEntity entity = response.getEntity();
+                assertNotNull(entity);
+                entity.consumeContent();
+                
+                if (r < 2) {
+                    assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response.getStatusLine().getStatusCode());
+                } else {
+                    assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
+                }
+                
+                if (!this.client.keepAlive(response)) {
+                    conn.close();
+                }
+            }
+            //Verify the connection metrics
+            HttpConnectionMetrics cm = conn.getMetrics();
+            assertEquals(reqNo, cm.getRequestCount());
+            assertEquals(reqNo, cm.getResponseCount());
+        } finally {
+            conn.close();
+            this.server.shutdown();
+        }
+    }
+    
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java
new file mode 100644
index 0000000..8cfcd5e
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.DynamicLayout;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import junit.framework.TestCase;
+
+
+public class TextLayoutTest extends TestCase {
+
+    protected String mString;
+    protected TextPaint mPaint;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mString = "The quick brown fox";
+        mPaint = new TextPaint();
+    }
+
+    @SmallTest
+    public void testStaticLayout() throws Exception {
+        Layout l = new StaticLayout(mString, mPaint, 200,
+                Layout.Alignment.ALIGN_NORMAL, 1, 0,
+                true);
+    }
+
+    @SmallTest
+    public void testDynamicLayoutTest() throws Exception {
+        Layout l = new DynamicLayout(mString, mPaint, 200,
+                Layout.Alignment.ALIGN_NORMAL, 1, 0,
+                true);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
new file mode 100644
index 0000000..51e841c
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import android.graphics.Paint;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.SpannedString;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.style.StyleSpan;
+import android.text.util.Rfc822Validator;
+import android.test.MoreAsserts;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * TextUtilsTest tests {@link TextUtils}.
+ */
+public class TextUtilsTest extends TestCase {
+
+    @SmallTest
+    public void testBasic() throws Exception {
+        assertEquals("", TextUtils.concat());
+        assertEquals("foo", TextUtils.concat("foo"));
+        assertEquals("foobar", TextUtils.concat("foo", "bar"));
+        assertEquals("foobarbaz", TextUtils.concat("foo", "bar", "baz"));
+
+        SpannableString foo = new SpannableString("foo");
+        foo.setSpan("foo", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+
+        SpannableString bar = new SpannableString("bar");
+        bar.setSpan("bar", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+
+        SpannableString baz = new SpannableString("baz");
+        baz.setSpan("baz", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+
+        assertEquals("foo", TextUtils.concat(foo).toString());
+        assertEquals("foobar", TextUtils.concat(foo, bar).toString());
+        assertEquals("foobarbaz", TextUtils.concat(foo, bar, baz).toString());
+
+        assertEquals(1, ((Spanned) TextUtils.concat(foo)).getSpanStart("foo"));
+
+        assertEquals(1, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("foo"));
+        assertEquals(4, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("bar"));
+
+        assertEquals(1, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("foo"));
+        assertEquals(4, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("bar"));
+        assertEquals(7, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("baz"));
+
+        assertTrue(TextUtils.concat("foo", "bar") instanceof String);
+        assertTrue(TextUtils.concat(foo, bar) instanceof SpannedString);
+    }
+
+    @SmallTest
+    public void testTemplateString() throws Exception {
+        CharSequence result;
+
+        result = TextUtils.expandTemplate("This is a ^1 of the ^2 broadcast ^3.",
+                                          "test", "emergency", "system");
+        assertEquals("This is a test of the emergency broadcast system.",
+                     result.toString());
+
+        result = TextUtils.expandTemplate("^^^1^^^2^3^a^1^^b^^^c",
+                                          "one", "two", "three");
+        assertEquals("^one^twothree^aone^b^^c",
+                     result.toString());
+
+        result = TextUtils.expandTemplate("^");
+        assertEquals("^", result.toString());
+
+        result = TextUtils.expandTemplate("^^");
+        assertEquals("^", result.toString());
+
+        result = TextUtils.expandTemplate("^^^");
+        assertEquals("^^", result.toString());
+
+        result = TextUtils.expandTemplate("shorter ^1 values ^2.", "a", "");
+        assertEquals("shorter a values .", result.toString());
+
+        try {
+            TextUtils.expandTemplate("Only ^1 value given, but ^2 used.", "foo");
+            fail();
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            TextUtils.expandTemplate("^1 value given, and ^0 used.", "foo");
+            fail();
+        } catch (IllegalArgumentException e) {
+        }
+
+        result = TextUtils.expandTemplate("^1 value given, and ^9 used.",
+                                          "one", "two", "three", "four", "five",
+                                          "six", "seven", "eight", "nine");
+        assertEquals("one value given, and nine used.", result.toString());
+
+        try {
+            TextUtils.expandTemplate("^1 value given, and ^10 used.",
+                                     "one", "two", "three", "four", "five",
+                                     "six", "seven", "eight", "nine", "ten");
+            fail();
+        } catch (IllegalArgumentException e) {
+        }
+
+        // putting carets in the values: expansion is not recursive.
+
+        result = TextUtils.expandTemplate("^2", "foo", "^^");
+        assertEquals("^^", result.toString());
+
+        result = TextUtils.expandTemplate("^^2", "foo", "1");
+        assertEquals("^2", result.toString());
+
+        result = TextUtils.expandTemplate("^1", "value with ^2 in it", "foo");
+        assertEquals("value with ^2 in it", result.toString());
+    }
+
+    /** Fail unless text+spans contains a span 'spanName' with the given start and end. */
+    private void checkContains(Spanned text, String[] spans, String spanName,
+                               int start, int end) throws Exception {
+        for (String i: spans) {
+            if (i.equals(spanName)) {
+                assertEquals(start, text.getSpanStart(i));
+                assertEquals(end, text.getSpanEnd(i));
+                return;
+            }
+        }
+        fail();
+    }
+
+    @SmallTest
+    public void testTemplateSpan() throws Exception {
+        SpannableString template;
+        Spanned result;
+        String[] spans;
+
+        // ordinary replacement
+
+        template = new SpannableString("a^1b");
+        template.setSpan("before", 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        template.setSpan("during", 1, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        template.setSpan("after", 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        template.setSpan("during+after", 1, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        result = (Spanned) TextUtils.expandTemplate(template, "foo");
+        assertEquals(5, result.length());
+        spans = result.getSpans(0, result.length(), String.class);
+
+        // value is one character longer, so span endpoints should change.
+        assertEquals(4, spans.length);
+        checkContains(result, spans, "before", 0, 1);
+        checkContains(result, spans, "during", 1, 4);
+        checkContains(result, spans, "after", 4, 5);
+        checkContains(result, spans, "during+after", 1, 5);
+
+
+        // replacement with empty string
+
+        result = (Spanned) TextUtils.expandTemplate(template, "");
+        assertEquals(2, result.length());
+        spans = result.getSpans(0, result.length(), String.class);
+
+        // the "during" span should disappear.
+        assertEquals(3, spans.length);
+        checkContains(result, spans, "before", 0, 1);
+        checkContains(result, spans, "after", 1, 2);
+        checkContains(result, spans, "during+after", 1, 2);
+    }
+
+    @SmallTest
+    public void testStringSplitterSimple() {
+        stringSplitterTestHelper("a,b,cde", new String[] {"a", "b", "cde"});
+    }
+
+    @SmallTest
+    public void testStringSplitterEmpty() {
+        stringSplitterTestHelper("", new String[] {});
+    }
+
+    @SmallTest
+    public void testStringSplitterWithLeadingEmptyString() {
+        stringSplitterTestHelper(",a,b,cde", new String[] {"", "a", "b", "cde"});
+    }
+
+    @SmallTest
+    public void testStringSplitterWithInternalEmptyString() {
+        stringSplitterTestHelper("a,b,,cde", new String[] {"a", "b", "", "cde"});
+    }
+
+    @SmallTest
+    public void testStringSplitterWithTrailingEmptyString() {
+        // A single trailing emtpy string should be ignored.
+        stringSplitterTestHelper("a,b,cde,", new String[] {"a", "b", "cde"});
+    }
+
+    private void stringSplitterTestHelper(String string, String[] expectedStrings) {
+        TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+        splitter.setString(string);
+        List<String> strings = Lists.newArrayList();
+        for (String s : splitter) {
+            strings.add(s);
+        }
+        MoreAsserts.assertEquals(expectedStrings, strings.toArray(new String[]{}));
+    }
+
+    @SmallTest
+    public void testTrim() {
+        String[] strings = { "abc", " abc", "  abc", "abc ", "abc  ",
+                             " abc ", "  abc  ", "\nabc\n", "\nabc", "abc\n" };
+
+        for (String s : strings) {
+            assertEquals(s.trim().length(), TextUtils.getTrimmedLength(s));
+        }
+    }
+
+    //==============================================================================================
+    // Email validator
+    //==============================================================================================
+    
+    @SmallTest
+    public void testEmailValidator() {
+        Rfc822Validator validator = new Rfc822Validator("gmail.com");
+        String[] validEmails = new String[] {
+            "a@b.com", "a@b.fr", "a+b@c.com", "a@b.info",
+        };
+        
+        for (String email : validEmails) {
+            assertTrue(email + " should be a valid email address", validator.isValid(email));
+        }
+        
+        String[] invalidEmails = new String[] {
+            "a", "a@b", "a b", "a@b.12"
+        };
+
+        for (String email : invalidEmails) {
+            assertFalse(email + " should not be a valid email address", validator.isValid(email));
+        }
+        
+        Map<String, String> fixes = Maps.newHashMap();
+        fixes.put("a", "<a@gmail.com>");
+        fixes.put("a b", "<ab@gmail.com>");
+        fixes.put("a@b", "<a@b>");
+        
+        for (Map.Entry<String, String> e : fixes.entrySet()) {
+            assertEquals(e.getValue(), validator.fixText(e.getKey()).toString());
+        }
+    }
+
+    @LargeTest
+    public void testEllipsize() {
+        CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog.";
+        CharSequence s2 = new Wrapper(s1);
+        Spannable s3 = new SpannableString(s1);
+        s3.setSpan(new StyleSpan(0), 5, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        TextPaint p = new TextPaint();
+
+        for (int i = 0; i < 100; i++) {
+            for (int j = 0; j < 3; j++) {
+                TextUtils.TruncateAt kind = null;
+
+                switch (j) {
+                case 0:
+                    kind = TextUtils.TruncateAt.START;
+                    break;
+
+                case 1:
+                    kind = TextUtils.TruncateAt.END;
+                    break;
+
+                case 2:
+                    kind = TextUtils.TruncateAt.MIDDLE;
+                    break;
+                }
+
+                String out1 = TextUtils.ellipsize(s1, p, i, kind).toString();
+                String out2 = TextUtils.ellipsize(s2, p, i, kind).toString();
+                String out3 = TextUtils.ellipsize(s3, p, i, kind).toString();
+
+                String keep1 = TextUtils.ellipsize(s1, p, i, kind, true, null).toString();
+                String keep2 = TextUtils.ellipsize(s2, p, i, kind, true, null).toString();
+                String keep3 = TextUtils.ellipsize(s3, p, i, kind, true, null).toString();
+
+                String trim1 = keep1.replace("\uFEFF", "");
+
+                // Are all normal output strings identical?
+                assertEquals("wid " + i + " pass " + j, out1, out2);
+                assertEquals("wid " + i + " pass " + j, out2, out3);
+
+                // Are preserved output strings identical?
+                assertEquals("wid " + i + " pass " + j, keep1, keep2);
+                assertEquals("wid " + i + " pass " + j, keep2, keep3);
+
+                // Does trimming padding from preserved yield normal?
+                assertEquals("wid " + i + " pass " + j, out1, trim1);
+
+                // Did preserved output strings preserve length?
+                assertEquals("wid " + i + " pass " + j, keep1.length(), s1.length());
+
+                // Does the output string actually fit in the space?
+                assertTrue("wid " + i + " pass " + j, p.measureText(out1) <= i);
+
+                // Is the padded output the same width as trimmed output?
+                assertTrue("wid " + i + " pass " + j, p.measureText(keep1) == p.measureText(out1));
+            }
+        }
+    }
+
+    /**
+     * CharSequence wrapper for testing the cases where text is copied into
+     * a char array instead of working from a String or a Spanned.
+     */
+    private static class Wrapper implements CharSequence {
+        private CharSequence mString;
+
+        public Wrapper(CharSequence s) {
+            mString = s;
+        }
+
+        public int length() {
+            return mString.length();
+        }
+
+        public char charAt(int off) {
+            return mString.charAt(off);
+        }
+
+        public String toString() {
+            return mString.toString();
+        }
+
+        public CharSequence subSequence(int start, int end) {
+            return new Wrapper(mString.subSequence(start, end));
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java
new file mode 100644
index 0000000..6fa8f4f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.SpannedString;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class TextViewPerformanceTest extends AndroidTestCase {
+
+    private String mString = "The quick brown fox";
+    private Canvas mCanvas;
+    private PerformanceTextView mTextView;
+    private Paint mPaint;
+    private PerformanceLabelView mLabelView;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        Bitmap mBitmap = Bitmap.createBitmap(320, 240, Bitmap.Config.RGB_565);
+        mCanvas = new Canvas(mBitmap);
+
+        ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(320, 240);
+
+        mLabelView = new PerformanceLabelView(mContext);
+        mLabelView.setText(mString);
+        mLabelView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240);
+        mLabelView.mySetFrame(320, 240);
+        mLabelView.setLayoutParams(p);
+        mLabelView.myDraw(mCanvas);
+
+        mPaint = new Paint();
+        mCanvas.save();
+        mTextView = new PerformanceTextView(mContext);
+        mTextView.setLayoutParams(p);
+        mTextView.setText(mString);
+        mTextView.mySetFrame(320, 240);
+        mTextView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240);
+    }
+
+    @MediumTest
+    public void testDrawTextViewLine() throws Exception {
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+    }
+
+    @SmallTest
+    public void testSpan() throws Exception {
+        CharSequence charSeq = new SpannedString(mString);
+        mTextView.setText(charSeq);
+
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+        mTextView.myDraw(mCanvas);
+    }
+
+    @SmallTest
+    public void testCanvasDrawText() throws Exception {
+        mCanvas.drawText(mString, 30, 30, mPaint);
+    }
+
+    @SmallTest
+    public void testLabelViewDraw() throws Exception {
+        mLabelView.myDraw(mCanvas);
+    }
+
+    private class PerformanceTextView extends TextView {
+        public PerformanceTextView(Context context) {
+            super(context);
+        }
+
+        final void myDraw(Canvas c) {
+            super.onDraw(c);
+        }
+
+        final void mySetFrame(int w, int h) {
+            super.setFrame(0, 0, w, h);
+        }
+    }
+
+    private class PerformanceLabelView extends LabelView {
+        public PerformanceLabelView(Context context) {
+            super(context);
+        }
+
+        final void myDraw(Canvas c) {
+            super.onDraw(c);
+        }
+
+        final void mySetFrame(int w, int h) {
+            super.setFrame(0, 0, w, h);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java
new file mode 100644
index 0000000..8e49118
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.GetChars;
+import android.widget.TextView;
+
+/**
+ * TextViewTest tests {@link TextView}.
+ */
+public class TextViewTest extends AndroidTestCase {
+
+    @SmallTest
+    public void testArray() throws Exception {
+        TextView tv = new TextView(mContext);
+
+        char[] c = new char[] { 'H', 'e', 'l', 'l', 'o', ' ',
+                                'W', 'o', 'r', 'l', 'd', '!' };
+
+        tv.setText(c, 1, 4);
+        CharSequence oldText = tv.getText();
+
+        tv.setText(c, 4, 5);
+        CharSequence newText = tv.getText();
+
+        assertTrue(newText == oldText);
+
+        assertEquals(5, newText.length());
+        assertEquals('o', newText.charAt(0));
+        assertEquals("o Wor", newText.toString());
+
+        assertEquals(" Wo", newText.subSequence(1, 4));
+
+        char[] c2 = new char[7];
+        ((GetChars) newText).getChars(1, 4, c2, 2);
+        assertEquals('\0', c2[1]);
+        assertEquals(' ', c2[2]);
+        assertEquals('W', c2[3]);
+        assertEquals('o', c2[4]);
+        assertEquals('\0', c2[5]);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java b/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java
new file mode 100644
index 0000000..220bc99e
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import junit.framework.TestCase;
+import android.graphics.Bitmap;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class ThreadBitmapTest extends TestCase {
+
+    @Override
+    protected void setUp() throws Exception {
+    }
+
+    @LargeTest
+    public void testCreation() {
+        for (int i = 0; i < 200; i++) {
+
+            new MThread().start();
+        }
+    }
+
+    class MThread extends Thread {
+        public Bitmap b;
+
+        public MThread() {
+            b = Bitmap.createBitmap(300, 300, Bitmap.Config.RGB_565);
+        }
+
+        public void run() {}
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java b/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java
new file mode 100644
index 0000000..110caa4
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.format.Time;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+public class TimeTest extends TestCase {
+
+    @SmallTest
+    public void testNormalize0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.parse("20060432T010203");
+        t.normalize(false /* use isDst */);
+//        System.out.println("got: " + t.year + '-'
+//                + t.month + '-' + t.monthDay
+//                + ' ' + t.hour + ':' + t.minute
+//                + ':' + t.second
+//                + "( " + t.isDst + ',' + t.gmtoff
+//                + ',' + t.weekDay
+//                + ',' + t.yearDay + ')');
+    }
+
+    private static class DateTest {
+        public int year1;
+        public int month1;
+        public int day1;
+        public int hour1;
+        public int minute1;
+        public int dst1;
+
+        public int offset;
+
+        public int year2;
+        public int month2;
+        public int day2;
+        public int hour2;
+        public int minute2;
+        public int dst2;
+
+        public DateTest(int year1, int month1, int day1, int hour1, int minute1, int dst1,
+                int offset, int year2, int month2, int day2, int hour2, int minute2,
+                int dst2) {
+            this.year1 = year1;
+            this.month1 = month1;
+            this.day1 = day1;
+            this.hour1 = hour1;
+            this.minute1 = minute1;
+            this.dst1 = dst1;
+            this.offset = offset;
+            this.year2 = year2;
+            this.month2 = month2;
+            this.day2 = day2;
+            this.hour2 = hour2;
+            this.minute2 = minute2;
+            this.dst2 = dst2;
+        }
+
+        public DateTest(int year1, int month1, int day1, int hour1, int minute1,
+                int offset, int year2, int month2, int day2, int hour2, int minute2) {
+            this.year1 = year1;
+            this.month1 = month1;
+            this.day1 = day1;
+            this.hour1 = hour1;
+            this.minute1 = minute1;
+            this.dst1 = -1;
+            this.offset = offset;
+            this.year2 = year2;
+            this.month2 = month2;
+            this.day2 = day2;
+            this.hour2 = hour2;
+            this.minute2 = minute2;
+            this.dst2 = -1;
+        }
+    }
+
+    // These tests assume that DST changes on Nov 4, 2007 at 2am (to 1am).
+
+    // The "offset" field in "dayTests" represents days.
+    // Use normalize(true) with these tests to change the date by 1 day.
+    private DateTest[] dayTests = {
+            // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11
+
+            // Nov 4, 12am + 0 day = Nov 4, 12am
+            // Nov 5, 12am + 0 day = Nov 5, 12am
+            new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0),
+            new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0),
+
+            // Nov 3, 12am + 1 day = Nov 4, 12am
+            // Nov 4, 12am + 1 day = Nov 5, 12am
+            // Nov 5, 12am + 1 day = Nov 6, 12am
+            new DateTest(2007, 10, 3, 0, 0, 1, 2007, 10, 4, 0, 0),
+            new DateTest(2007, 10, 4, 0, 0, 1, 2007, 10, 5, 0, 0),
+            new DateTest(2007, 10, 5, 0, 0, 1, 2007, 10, 6, 0, 0),
+
+            // Nov 3, 1am + 1 day = Nov 4, 1am
+            // Nov 4, 1am + 1 day = Nov 5, 1am
+            // Nov 5, 1am + 1 day = Nov 6, 1am
+            new DateTest(2007, 10, 3, 1, 0, 1, 2007, 10, 4, 1, 0),
+            new DateTest(2007, 10, 4, 1, 0, 1, 2007, 10, 5, 1, 0),
+            new DateTest(2007, 10, 5, 1, 0, 1, 2007, 10, 6, 1, 0),
+
+            // Nov 3, 2am + 1 day = Nov 4, 2am
+            // Nov 4, 2am + 1 day = Nov 5, 2am
+            // Nov 5, 2am + 1 day = Nov 6, 2am
+            new DateTest(2007, 10, 3, 2, 0, 1, 2007, 10, 4, 2, 0),
+            new DateTest(2007, 10, 4, 2, 0, 1, 2007, 10, 5, 2, 0),
+            new DateTest(2007, 10, 5, 2, 0, 1, 2007, 10, 6, 2, 0),
+    };
+
+    // The "offset" field in "minuteTests" represents minutes.
+    // Use normalize(false) with these tests.
+    private DateTest[] minuteTests = {
+            // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11
+
+            // Nov 4, 12am + 0 minutes = Nov 4, 12am
+            // Nov 5, 12am + 0 minutes = Nov 5, 12am
+            new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0),
+            new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0),
+
+            // Nov 3, 12am + 60 minutes = Nov 3, 1am
+            // Nov 4, 12am + 60 minutes = Nov 4, 1am
+            // Nov 5, 12am + 60 minutes = Nov 5, 1am
+            new DateTest(2007, 10, 3, 0, 0, 60, 2007, 10, 3, 1, 0),
+            new DateTest(2007, 10, 4, 0, 0, 60, 2007, 10, 4, 1, 0),
+            new DateTest(2007, 10, 5, 0, 0, 60, 2007, 10, 5, 1, 0),
+
+            // Nov 3, 1am + 60 minutes = Nov 3, 2am
+            // Nov 4, 1am (PDT) + 30 minutes = Nov 4, 1:30am (PDT)
+            // Nov 4, 1am (PDT) + 60 minutes = Nov 4, 1am (PST)
+            new DateTest(2007, 10, 3, 1, 0, 60, 2007, 10, 3, 2, 0),
+            new DateTest(2007, 10, 4, 1, 0, 1, 30, 2007, 10, 4, 1, 30, 1),
+            new DateTest(2007, 10, 4, 1, 0, 1, 60, 2007, 10, 4, 1, 0, 0),
+
+            // Nov 4, 1:30am (PDT) + 15 minutes = Nov 4, 1:45am (PDT)
+            // Nov 4, 1:30am (PDT) + 30 minutes = Nov 4, 1:00am (PST)
+            // Nov 4, 1:30am (PDT) + 60 minutes = Nov 4, 1:30am (PST)
+            new DateTest(2007, 10, 4, 1, 30, 1, 15, 2007, 10, 4, 1, 45, 1),
+            new DateTest(2007, 10, 4, 1, 30, 1, 30, 2007, 10, 4, 1, 0, 0),
+            new DateTest(2007, 10, 4, 1, 30, 1, 60, 2007, 10, 4, 1, 30, 0),
+
+            // Nov 4, 1:30am (PST) + 15 minutes = Nov 4, 1:45am (PST)
+            // Nov 4, 1:30am (PST) + 30 minutes = Nov 4, 2:00am (PST)
+            // Nov 5, 1am + 60 minutes = Nov 5, 2am
+            new DateTest(2007, 10, 4, 1, 30, 0, 15, 2007, 10, 4, 1, 45, 0),
+            new DateTest(2007, 10, 4, 1, 30, 0, 30, 2007, 10, 4, 2, 0, 0),
+            new DateTest(2007, 10, 5, 1, 0, 60, 2007, 10, 5, 2, 0),
+
+            // Nov 3, 2am + 60 minutes = Nov 3, 3am
+            // Nov 4, 2am + 30 minutes = Nov 4, 2:30am
+            // Nov 4, 2am + 60 minutes = Nov 4, 3am
+            // Nov 5, 2am + 60 minutes = Nov 5, 3am
+            new DateTest(2007, 10, 3, 2, 0, 60, 2007, 10, 3, 3, 0),
+            new DateTest(2007, 10, 4, 2, 0, 30, 2007, 10, 4, 2, 30),
+            new DateTest(2007, 10, 4, 2, 0, 60, 2007, 10, 4, 3, 0),
+            new DateTest(2007, 10, 5, 2, 0, 60, 2007, 10, 5, 3, 0),
+    };
+
+    @SmallTest
+    public void testNormalize1() throws Exception {
+        Time local = new Time("America/Los_Angeles");
+
+        int len = dayTests.length;
+        for (int index = 0; index < len; index++) {
+            DateTest test = dayTests[index];
+            local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
+            // call normalize() to make sure that isDst is set
+            local.normalize(false /* use isDst */);
+            local.monthDay += test.offset;
+            local.normalize(true /* ignore isDst */);
+            if (local.year != test.year2 || local.month != test.month2
+                    || local.monthDay != test.day2 || local.hour != test.hour2
+                    || local.minute != test.minute2) {
+                String expectedTime = String.format("%d-%02d-%02d %02d:%02d",
+                        test.year2, test.month2, test.day2, test.hour2, test.minute2);
+                String actualTime = String.format("%d-%02d-%02d %02d:%02d",
+                        local.year, local.month, local.monthDay, local.hour, local.minute);
+                throw new RuntimeException(
+                        "day test index " + index + ", normalize(): expected local " + expectedTime
+                                + " got: " + actualTime);
+            }
+
+            local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
+            // call normalize() to make sure that isDst is set
+            local.normalize(false /* use isDst */);
+            local.monthDay += test.offset;
+            long millis = local.toMillis(true /* ignore isDst */);
+            local.set(millis);
+            if (local.year != test.year2 || local.month != test.month2
+                    || local.monthDay != test.day2 || local.hour != test.hour2
+                    || local.minute != test.minute2) {
+                String expectedTime = String.format("%d-%02d-%02d %02d:%02d",
+                        test.year2, test.month2, test.day2, test.hour2, test.minute2);
+                String actualTime = String.format("%d-%02d-%02d %02d:%02d",
+                        local.year, local.month, local.monthDay, local.hour, local.minute);
+                throw new RuntimeException(
+                        "day test index " + index + ", toMillis(): expected local " + expectedTime
+                                + " got: " + actualTime);
+            }
+        }
+
+        len = minuteTests.length;
+        for (int index = 0; index < len; index++) {
+            DateTest test = minuteTests[index];
+            local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
+            local.isDst = test.dst1;
+            // call normalize() to make sure that isDst is set
+            local.normalize(false /* use isDst */);
+            if (test.dst2 == -1) test.dst2 = local.isDst;
+            local.minute += test.offset;
+            local.normalize(false /* use isDst */);
+            if (local.year != test.year2 || local.month != test.month2
+                    || local.monthDay != test.day2 || local.hour != test.hour2
+                    || local.minute != test.minute2 || local.isDst != test.dst2) {
+                String expectedTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d",
+                        test.year2, test.month2, test.day2, test.hour2, test.minute2,
+                        test.dst2);
+                String actualTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d",
+                        local.year, local.month, local.monthDay, local.hour, local.minute,
+                        local.isDst);
+                throw new RuntimeException(
+                        "minute test index " + index + ", normalize(): expected local " + expectedTime
+                                + " got: " + actualTime);
+            }
+
+            local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
+            local.isDst = test.dst1;
+            // call normalize() to make sure that isDst is set
+            local.normalize(false /* use isDst */);
+            if (test.dst2 == -1) test.dst2 = local.isDst;
+            local.minute += test.offset;
+            long millis = local.toMillis(false /* use isDst */);
+            local.set(millis);
+            if (local.year != test.year2 || local.month != test.month2
+                    || local.monthDay != test.day2 || local.hour != test.hour2
+                    || local.minute != test.minute2 || local.isDst != test.dst2) {
+                String expectedTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d",
+                        test.year2, test.month2, test.day2, test.hour2, test.minute2,
+                        test.dst2);
+                String actualTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d",
+                        local.year, local.month, local.monthDay, local.hour, local.minute,
+                        local.isDst);
+                throw new RuntimeException(
+                        "minute test index " + index + ", toMillis(): expected local " + expectedTime
+                                + " got: " + actualTime);
+            }
+        }
+    }
+
+    @SmallTest
+    public void testSwitchTimezone0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.parse("20061005T120000");
+        t.switchTimezone("America/Los_Angeles");
+        // System.out.println("got: " + t);
+    }
+
+    @SmallTest
+    public void testCtor0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        assertEquals(Time.TIMEZONE_UTC, t.timezone);
+    }
+
+    @SmallTest
+    public void testGetActualMaximum0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        int r = t.getActualMaximum(Time.SECOND);
+        // System.out.println("r=" + r);
+    }
+
+    @SmallTest
+    public void testClear0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.clear(Time.TIMEZONE_UTC);
+    }
+
+    @SmallTest
+    public void testCompare0() throws Exception {
+        Time a = new Time(Time.TIMEZONE_UTC);
+        Time b = new Time("America/Los_Angeles");
+        int r = Time.compare(a, b);
+        // System.out.println("r=" + r);
+    }
+
+    @SmallTest
+    public void testFormat0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        String r = t.format("%Y%m%dT%H%M%S");
+        // System.out.println("r='" + r + "'");
+    }
+
+    @SmallTest
+    public void testToString0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        String r = t.toString();
+        // System.out.println("r='" + r + "'");
+    }
+
+    @SmallTest
+    public void testGetCurrentTimezone0() throws Exception {
+        String r = Time.getCurrentTimezone();
+        // System.out.println("r='" + r + "'");
+    }
+
+    @SmallTest
+    public void testSetToNow0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.setToNow();
+        // System.out.println("t=" + t);
+    }
+
+    @SmallTest
+    public void testMillis0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.set(0, 0, 0, 1, 1, 2006);
+        long r = t.toMillis(true /* ignore isDst */);
+        // System.out.println("r=" + r);
+        t.set(1, 0, 0, 1, 1, 2006);
+        r = t.toMillis(true /* ignore isDst */);
+        // System.out.println("r=" + r);
+    }
+
+    @SmallTest
+    public void testMillis1() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.set(1, 0, 0, 1, 0, 1970);
+        long r = t.toMillis(true /* ignore isDst */);
+        // System.out.println("r=" + r);
+    }
+
+    @SmallTest
+    public void testParse0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.parse("12345678T901234");
+        // System.out.println("t=" + t);
+    }
+
+    @SmallTest
+    public void testSet0() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.set(1000L);
+        // System.out.println("t.year=" + t.year);
+        // System.out.println("t=" + t);
+        t.set(2000L);
+        // System.out.println("t=" + t);
+        t.set(1000L * 60);
+        // System.out.println("t=" + t);
+        t.set((1000L * 60 * 60 * 24) + 1000L);
+        // System.out.println("t=" + t);
+    }
+
+    @SmallTest
+    public void testSet1() throws Exception {
+        Time t = new Time(Time.TIMEZONE_UTC);
+        t.set(1, 2, 3, 4, 5, 6);
+        // System.out.println("t=" + t);
+    }
+    
+    // Timezones that cover the world.  Some GMT offsets occur more than
+    // once in case some cities decide to change their GMT offset.
+    private static final String[] mTimeZones = {
+        "Pacific/Kiritimati",
+        "Pacific/Enderbury",
+        "Pacific/Fiji",
+        "Antarctica/South_Pole",
+        "Pacific/Norfolk",
+        "Pacific/Ponape",
+        "Asia/Magadan",
+        "Australia/Lord_Howe",
+        "Australia/Sydney",
+        "Australia/Adelaide",
+        "Asia/Tokyo",
+        "Asia/Seoul",
+        "Asia/Taipei",
+        "Asia/Singapore",
+        "Asia/Hong_Kong",
+        "Asia/Saigon",
+        "Asia/Bangkok",
+        "Indian/Cocos",
+        "Asia/Rangoon",
+        "Asia/Omsk",
+        "Antarctica/Mawson",
+        "Asia/Colombo",
+        "Asia/Calcutta",
+        "Asia/Oral",
+        "Asia/Kabul",
+        "Asia/Dubai",
+        "Asia/Tehran",
+        "Europe/Moscow",
+        "Asia/Baghdad",
+        "Africa/Mogadishu",
+        "Europe/Athens",
+        "Africa/Cairo",
+        "Europe/Rome",
+        "Europe/Berlin",
+        "Europe/Amsterdam",
+        "Africa/Tunis",
+        "Europe/London",
+        "Europe/Dublin",
+        "Atlantic/St_Helena",
+        "Africa/Monrovia",
+        "Africa/Accra",
+        "Atlantic/Azores",
+        "Atlantic/South_Georgia",
+        "America/Noronha",
+        "America/Sao_Paulo",
+        "America/Cayenne",
+        "America/St_Johns",
+        "America/Puerto_Rico",
+        "America/Aruba",
+        "America/New_York",
+        "America/Chicago",
+        "America/Denver",
+        "America/Los_Angeles",
+        "America/Anchorage",
+        "Pacific/Marquesas",
+        "America/Adak",
+        "Pacific/Honolulu",
+        "Pacific/Midway",
+    };
+    
+    @Suppress
+    public void disableTestGetJulianDay() throws Exception {
+        Time time = new Time();
+
+        // For each day of the year, and for each timezone, get the Julian
+        // day for 12am and then check that if we change the time we get the
+        // same Julian day.
+        for (int monthDay = 1; monthDay <= 366; monthDay++) {
+            for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) {
+                // We leave the "month" as zero because we are changing the
+                // "monthDay" from 1 to 366.  The call to normalize() will
+                // then change the "month" (but we don't really care).
+                time.set(0, 0, 0, monthDay, 0, 2008);
+                time.timezone = mTimeZones[zoneIndex];
+                long millis = time.normalize(true);
+                if (zoneIndex == 0) {
+                    Log.i("TimeTest", time.format("%B %d, %Y"));
+                }
+                
+                // This is the Julian day for 12am for this day of the year
+                int julianDay = Time.getJulianDay(millis, time.gmtoff);
+
+                // Change the time during the day and check that we get the same
+                // Julian day.
+                for (int hour = 0; hour < 24; hour++) {
+                    for (int minute = 0; minute < 60; minute += 15) {
+                        time.set(0, minute, hour, monthDay, 0, 2008);
+                        millis = time.normalize(true);
+                        int day = Time.getJulianDay(millis, time.gmtoff);
+                        if (day != julianDay) {
+                            Log.e("TimeTest", "Julian day: " + day + " at time "
+                                    + time.hour + ":" + time.minute
+                                    + " != today's Julian day: " + julianDay
+                                    + " timezone: " + time.timezone);
+                        }
+                        assertEquals(day, julianDay);
+                    }
+                }
+            }
+        }
+    }
+    
+    @Suppress
+    public void disableTestSetJulianDay() throws Exception {
+        Time time = new Time();
+        
+        // For each day of the year in 2008, and for each timezone,
+        // test that we can set the Julian day correctly.
+        for (int monthDay = 1; monthDay <= 366; monthDay++) {
+            for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) {
+                // We leave the "month" as zero because we are changing the
+                // "monthDay" from 1 to 366.  The call to normalize() will
+                // then change the "month" (but we don't really care).
+                time.set(0, 0, 0, monthDay, 0, 2008);
+                time.timezone = mTimeZones[zoneIndex];
+                long millis = time.normalize(true);
+                if (zoneIndex == 0) {
+                    Log.i("TimeTest", time.format("%B %d, %Y"));
+                }
+                int julianDay = Time.getJulianDay(millis, time.gmtoff);
+                
+                time.setJulianDay(julianDay);
+                
+                // Some places change daylight saving time at 12am and so there
+                // is no 12am on some days in some timezones.  In those cases,
+                // the time is set to 1am.
+                // Examples: Africa/Cairo on April 25, 2008
+                //  America/Sao_Paulo on October 12, 2008
+                //  Atlantic/Azores on March 30, 2008
+                assertTrue(time.hour == 0 || time.hour == 1);
+                assertEquals(0, time.minute);
+                assertEquals(0, time.second);
+
+                millis = time.toMillis(false);
+                int day = Time.getJulianDay(millis, time.gmtoff);
+                if (day != julianDay) {
+                    Log.i("TimeTest", "Error: gmtoff " + (time.gmtoff / 3600.0)
+                            + " day " + julianDay
+                            + " millis " + millis
+                            + " " + time.format("%B %d, %Y") + " " + time.timezone);
+                }
+                assertEquals(day, julianDay);
+            }
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java
new file mode 100644
index 0000000..6ba64fd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.unit_tests;
+
+import junit.framework.TestCase;
+
+import android.util.TimeUtils;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * TimeUtilsTest tests the time zone guesser.
+ */
+public class TimeUtilsTest extends TestCase {
+    public void testMainstream() throws Exception {
+        String[] mainstream = new String[] {
+            "America/New_York", // Eastern
+            "America/Chicago", // Central
+            "America/Denver", // Mountain
+            "America/Los_Angeles", // Pacific
+            "America/Anchorage", // Alaska
+            "Pacific/Honolulu", // Hawaii, no DST
+        };
+
+        for (String name : mainstream) {
+            TimeZone tz = TimeZone.getTimeZone(name);
+            Calendar c = Calendar.getInstance(tz);
+            TimeZone guess;
+
+            c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00);
+            guess = guess(c, "us");
+            assertEquals(name, guess.getID());
+
+            c.set(2009, Calendar.JANUARY, 20, 12, 00, 00);
+            guess = guess(c, "us");
+            assertEquals(name, guess.getID());
+        }
+    }
+
+    public void testWeird() throws Exception {
+        String[] weird = new String[] {
+            "America/Phoenix", // Mountain, no DST
+            "America/Adak", // Same as Hawaii, but with DST
+        };
+
+        for (String name : weird) {
+            TimeZone tz = TimeZone.getTimeZone(name);
+            Calendar c = Calendar.getInstance(tz);
+            TimeZone guess;
+
+            c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00);
+            guess = guess(c, "us");
+            assertEquals(name, guess.getID());
+        }
+    }
+
+    public void testOld() throws Exception {
+        String[] old = new String[] {
+            "America/Indiana/Indianapolis", // Eastern, formerly no DST
+        };
+
+        for (String name : old) {
+            TimeZone tz = TimeZone.getTimeZone(name);
+            Calendar c = Calendar.getInstance(tz);
+            TimeZone guess;
+
+            c.set(2005, Calendar.OCTOBER, 20, 12, 00, 00);
+            guess = guess(c, "us");
+            assertEquals(name, guess.getID());
+        }
+    }
+
+    public void testWorld() throws Exception {
+        String[] world = new String[] {
+            "ad", "Europe/Andorra",
+            "ae", "Asia/Dubai",
+            "af", "Asia/Kabul",
+            "ag", "America/Antigua",
+            "ai", "America/Anguilla",
+            "al", "Europe/Tirane",
+            "am", "Asia/Yerevan",
+            "an", "America/Curacao",
+            "ao", "Africa/Luanda",
+            "aq", "Antarctica/McMurdo",
+            "aq", "Antarctica/DumontDUrville",
+            "aq", "Antarctica/Casey",
+            "aq", "Antarctica/Davis",
+            "aq", "Antarctica/Mawson",
+            "aq", "Antarctica/Syowa",
+            "aq", "Antarctica/Rothera",
+            "aq", "Antarctica/Palmer",
+            "ar", "America/Argentina/Buenos_Aires",
+            "as", "Pacific/Pago_Pago",
+            "at", "Europe/Vienna",
+            "au", "Australia/Sydney",
+            "au", "Australia/Adelaide",
+            "au", "Australia/Perth",
+            "au", "Australia/Eucla",
+            "aw", "America/Aruba",
+            "ax", "Europe/Mariehamn",
+            "az", "Asia/Baku",
+            "ba", "Europe/Sarajevo",
+            "bb", "America/Barbados",
+            "bd", "Asia/Dhaka",
+            "be", "Europe/Brussels",
+            "bf", "Africa/Ouagadougou",
+            "bg", "Europe/Sofia",
+            "bh", "Asia/Bahrain",
+            "bi", "Africa/Bujumbura",
+            "bj", "Africa/Porto-Novo",
+            "bm", "Atlantic/Bermuda",
+            "bn", "Asia/Brunei",
+            "bo", "America/La_Paz",
+            "br", "America/Noronha",
+            "br", "America/Sao_Paulo",
+            "br", "America/Manaus",
+            "bs", "America/Nassau",
+            "bt", "Asia/Thimphu",
+            "bw", "Africa/Gaborone",
+            "by", "Europe/Minsk",
+            "bz", "America/Belize",
+            "ca", "America/St_Johns",
+            "ca", "America/Halifax",
+            "ca", "America/Toronto",
+            "ca", "America/Winnipeg",
+            "ca", "America/Edmonton",
+            "ca", "America/Vancouver",
+            "cc", "Indian/Cocos",
+            "cd", "Africa/Lubumbashi",
+            "cd", "Africa/Kinshasa",
+            "cf", "Africa/Bangui",
+            "cg", "Africa/Brazzaville",
+            "ch", "Europe/Zurich",
+            "ci", "Africa/Abidjan",
+            "ck", "Pacific/Rarotonga",
+            "cl", "America/Santiago",
+            "cl", "Pacific/Easter",
+            "cm", "Africa/Douala",
+            "cn", "Asia/Shanghai",
+            "co", "America/Bogota",
+            "cr", "America/Costa_Rica",
+            "cu", "America/Havana",
+            "cv", "Atlantic/Cape_Verde",
+            "cx", "Indian/Christmas",
+            "cy", "Asia/Nicosia",
+            "cz", "Europe/Prague",
+            "de", "Europe/Berlin",
+            "dj", "Africa/Djibouti",
+            "dk", "Europe/Copenhagen",
+            "dm", "America/Dominica",
+            "do", "America/Santo_Domingo",
+            "dz", "Africa/Algiers",
+            "ec", "America/Guayaquil",
+            "ec", "Pacific/Galapagos",
+            "ee", "Europe/Tallinn",
+            "eg", "Africa/Cairo",
+            "eh", "Africa/El_Aaiun",
+            "er", "Africa/Asmara",
+            "es", "Europe/Madrid",
+            "es", "Atlantic/Canary",
+            "et", "Africa/Addis_Ababa",
+            "fi", "Europe/Helsinki",
+            "fj", "Pacific/Fiji",
+            "fk", "Atlantic/Stanley",
+            "fm", "Pacific/Ponape",
+            "fm", "Pacific/Truk",
+            "fo", "Atlantic/Faroe",
+            "fr", "Europe/Paris",
+            "ga", "Africa/Libreville",
+            "gb", "Europe/London",
+            "gd", "America/Grenada",
+            "ge", "Asia/Tbilisi",
+            "gf", "America/Cayenne",
+            "gg", "Europe/Guernsey",
+            "gh", "Africa/Accra",
+            "gi", "Europe/Gibraltar",
+            "gl", "America/Danmarkshavn",
+            "gl", "America/Scoresbysund",
+            "gl", "America/Godthab",
+            "gl", "America/Thule",
+            "gm", "Africa/Banjul",
+            "gn", "Africa/Conakry",
+            "gp", "America/Guadeloupe",
+            "gq", "Africa/Malabo",
+            "gr", "Europe/Athens",
+            "gs", "Atlantic/South_Georgia",
+            "gt", "America/Guatemala",
+            "gu", "Pacific/Guam",
+            "gw", "Africa/Bissau",
+            "gy", "America/Guyana",
+            "hk", "Asia/Hong_Kong",
+            "hn", "America/Tegucigalpa",
+            "hr", "Europe/Zagreb",
+            "ht", "America/Port-au-Prince",
+            "hu", "Europe/Budapest",
+            "id", "Asia/Jayapura",
+            "id", "Asia/Makassar",
+            "id", "Asia/Jakarta",
+            "ie", "Europe/Dublin",
+            "il", "Asia/Jerusalem",
+            "im", "Europe/Isle_of_Man",
+            "in", "Asia/Calcutta",
+            "io", "Indian/Chagos",
+            "iq", "Asia/Baghdad",
+            "ir", "Asia/Tehran",
+            "is", "Atlantic/Reykjavik",
+            "it", "Europe/Rome",
+            "je", "Europe/Jersey",
+            "jm", "America/Jamaica",
+            "jo", "Asia/Amman",
+            "jp", "Asia/Tokyo",
+            "ke", "Africa/Nairobi",
+            "kg", "Asia/Bishkek",
+            "kh", "Asia/Phnom_Penh",
+            "ki", "Pacific/Kiritimati",
+            "ki", "Pacific/Enderbury",
+            "ki", "Pacific/Tarawa",
+            "km", "Indian/Comoro",
+            "kn", "America/St_Kitts",
+            "kp", "Asia/Pyongyang",
+            "kr", "Asia/Seoul",
+            "kw", "Asia/Kuwait",
+            "ky", "America/Cayman",
+            "kz", "Asia/Almaty",
+            "kz", "Asia/Aqtau",
+            "la", "Asia/Vientiane",
+            "lb", "Asia/Beirut",
+            "lc", "America/St_Lucia",
+            "li", "Europe/Vaduz",
+            "lk", "Asia/Colombo",
+            "lr", "Africa/Monrovia",
+            "ls", "Africa/Maseru",
+            "lt", "Europe/Vilnius",
+            "lu", "Europe/Luxembourg",
+            "lv", "Europe/Riga",
+            "ly", "Africa/Tripoli",
+            "ma", "Africa/Casablanca",
+            "mc", "Europe/Monaco",
+            "md", "Europe/Chisinau",
+            "me", "Europe/Podgorica",
+            "mg", "Indian/Antananarivo",
+            "mh", "Pacific/Majuro",
+            "mk", "Europe/Skopje",
+            "ml", "Africa/Bamako",
+            "mm", "Asia/Rangoon",
+            "mn", "Asia/Choibalsan",
+            "mn", "Asia/Hovd",
+            "mo", "Asia/Macau",
+            "mp", "Pacific/Saipan",
+            "mq", "America/Martinique",
+            "mr", "Africa/Nouakchott",
+            "ms", "America/Montserrat",
+            "mt", "Europe/Malta",
+            "mu", "Indian/Mauritius",
+            "mv", "Indian/Maldives",
+            "mw", "Africa/Blantyre",
+            "mx", "America/Mexico_City",
+            "mx", "America/Chihuahua",
+            "mx", "America/Tijuana",
+            "my", "Asia/Kuala_Lumpur",
+            "mz", "Africa/Maputo",
+            "na", "Africa/Windhoek",
+            "nc", "Pacific/Noumea",
+            "ne", "Africa/Niamey",
+            "nf", "Pacific/Norfolk",
+            "ng", "Africa/Lagos",
+            "ni", "America/Managua",
+            "nl", "Europe/Amsterdam",
+            "no", "Europe/Oslo",
+            "np", "Asia/Katmandu",
+            "nr", "Pacific/Nauru",
+            "nu", "Pacific/Niue",
+            "nz", "Pacific/Auckland",
+            "nz", "Pacific/Chatham",
+            "om", "Asia/Muscat",
+            "pa", "America/Panama",
+            "pe", "America/Lima",
+            "pf", "Pacific/Gambier",
+            "pf", "Pacific/Marquesas",
+            "pf", "Pacific/Tahiti",
+            "pg", "Pacific/Port_Moresby",
+            "ph", "Asia/Manila",
+            "pk", "Asia/Karachi",
+            "pl", "Europe/Warsaw",
+            "pm", "America/Miquelon",
+            "pn", "Pacific/Pitcairn",
+            "pr", "America/Puerto_Rico",
+            "ps", "Asia/Gaza",
+            "pt", "Europe/Lisbon",
+            "pt", "Atlantic/Azores",
+            "pw", "Pacific/Palau",
+            "py", "America/Asuncion",
+            "qa", "Asia/Qatar",
+            "re", "Indian/Reunion",
+            "ro", "Europe/Bucharest",
+            "rs", "Europe/Belgrade",
+            "ru", "Asia/Kamchatka",
+            "ru", "Asia/Magadan",
+            "ru", "Asia/Vladivostok",
+            "ru", "Asia/Yakutsk",
+            "ru", "Asia/Irkutsk",
+            "ru", "Asia/Krasnoyarsk",
+            "ru", "Asia/Novosibirsk",
+            "ru", "Asia/Yekaterinburg",
+            "ru", "Europe/Samara",
+            "ru", "Europe/Moscow",
+            "ru", "Europe/Kaliningrad",
+            "rw", "Africa/Kigali",
+            "sa", "Asia/Riyadh",
+            "sb", "Pacific/Guadalcanal",
+            "sc", "Indian/Mahe",
+            "sd", "Africa/Khartoum",
+            "se", "Europe/Stockholm",
+            "sg", "Asia/Singapore",
+            "sh", "Atlantic/St_Helena",
+            "si", "Europe/Ljubljana",
+            "sj", "Arctic/Longyearbyen",
+            "sk", "Europe/Bratislava",
+            "sl", "Africa/Freetown",
+            "sm", "Europe/San_Marino",
+            "sn", "Africa/Dakar",
+            "so", "Africa/Mogadishu",
+            "sr", "America/Paramaribo",
+            "st", "Africa/Sao_Tome",
+            "sv", "America/El_Salvador",
+            "sy", "Asia/Damascus",
+            "sz", "Africa/Mbabane",
+            "tc", "America/Grand_Turk",
+            "td", "Africa/Ndjamena",
+            "tf", "Indian/Kerguelen",
+            "tg", "Africa/Lome",
+            "th", "Asia/Bangkok",
+            "tj", "Asia/Dushanbe",
+            "tk", "Pacific/Fakaofo",
+            "tl", "Asia/Dili",
+            "tm", "Asia/Ashgabat",
+            "tn", "Africa/Tunis",
+            "to", "Pacific/Tongatapu",
+            "tr", "Europe/Istanbul",
+            "tt", "America/Port_of_Spain",
+            "tv", "Pacific/Funafuti",
+            "tw", "Asia/Taipei",
+            "tz", "Africa/Dar_es_Salaam",
+            "ua", "Europe/Kiev",
+            "ug", "Africa/Kampala",
+            "um", "Pacific/Wake",
+            "um", "Pacific/Johnston",
+            "um", "Pacific/Midway",
+            "us", "America/New_York",
+            "us", "America/Chicago",
+            "us", "America/Denver",
+            "us", "America/Los_Angeles",
+            "us", "America/Anchorage",
+            "us", "Pacific/Honolulu",
+            "uy", "America/Montevideo",
+            "uz", "Asia/Tashkent",
+            "va", "Europe/Vatican",
+            "vc", "America/St_Vincent",
+            "ve", "America/Caracas",
+            "vg", "America/Tortola",
+            "vi", "America/St_Thomas",
+            "vn", "Asia/Saigon",
+            "vu", "Pacific/Efate",
+            "wf", "Pacific/Wallis",
+            "ws", "Pacific/Apia",
+            "ye", "Asia/Aden",
+            "yt", "Indian/Mayotte",
+            "za", "Africa/Johannesburg",
+            "zm", "Africa/Lusaka",
+            "zw", "Africa/Harare",
+        };
+
+        for (int i = 0; i < world.length; i += 2) {
+            String country = world[i];
+            String name = world[i + 1];
+
+            TimeZone tz = TimeZone.getTimeZone(name);
+            Calendar c = Calendar.getInstance(tz);
+            TimeZone guess;
+
+            c.set(2009, Calendar.JULY, 20, 12, 00, 00);
+            guess = guess(c, country);
+            assertEquals(name, guess.getID());
+
+            c.set(2009, Calendar.JANUARY, 20, 12, 00, 00);
+            guess = guess(c, country);
+            assertEquals(name, guess.getID());
+        }
+    }
+
+    public void testWorldWeird() throws Exception {
+        String[] world = new String[] {
+            // Distinguisable from Sydney only when DST not in effect
+            "au", "Australia/Lord_Howe",
+        };
+
+        for (int i = 0; i < world.length; i += 2) {
+            String country = world[i];
+            String name = world[i + 1];
+
+            TimeZone tz = TimeZone.getTimeZone(name);
+            Calendar c = Calendar.getInstance(tz);
+            TimeZone guess;
+
+            c.set(2009, Calendar.JULY, 20, 12, 00, 00);
+            guess = guess(c, country);
+            assertEquals(name, guess.getID());
+        }
+    }
+
+    private static TimeZone guess(Calendar c, String country) {
+        return TimeUtils.getTimeZone(c.get(c.ZONE_OFFSET) + c.get(c.DST_OFFSET),
+                                     c.get(c.DST_OFFSET) != 0,
+                                     c.getTimeInMillis(),
+                                     country);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java b/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java
new file mode 100644
index 0000000..6705080
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.os.Debug;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+/**
+ * This class is used to test the native tracing support.  Run this test
+ * while tracing on the emulator and then run traceview to view the trace.
+ */
+public class TraceTest extends AndroidTestCase
+{
+    private static final String TAG = "TraceTest";
+    private int eMethodCalls = 0;
+    private int fMethodCalls = 0;
+    private int gMethodCalls = 0;
+    
+    @SmallTest
+    public void testNativeTracingFromJava()
+    {
+        long start = System.currentTimeMillis();
+        Debug.startNativeTracing();
+        //nativeMethod();
+        int count = 0;
+        for (int ii = 0; ii < 20; ii++) {
+            count = eMethod();
+        }
+        Debug.stopNativeTracing();
+        long end = System.currentTimeMillis();
+        long elapsed = end - start;
+        Log.i(TAG, "elapsed millis: " + elapsed);
+        Log.i(TAG, "eMethod calls: " + eMethodCalls
+                + " fMethod calls: " + fMethodCalls
+                + " gMethod calls: " + gMethodCalls);
+    }
+    
+    // This should not run in the automated suite.
+    @Suppress
+    public void disableTestNativeTracingFromC()
+    {
+        long start = System.currentTimeMillis();
+        nativeMethodAndStartTracing();
+        long end = System.currentTimeMillis();
+        long elapsed = end - start;
+        Log.i(TAG, "elapsed millis: " + elapsed);
+    }
+
+    native void nativeMethod();
+    native void nativeMethodAndStartTracing();
+    
+    @LargeTest
+    public void testMethodTracing()
+    {
+        long start = System.currentTimeMillis();
+        Debug.startMethodTracing("traceTest");
+        topMethod();
+        Debug.stopMethodTracing();
+        long end = System.currentTimeMillis();
+        long elapsed = end - start;
+        Log.i(TAG, "elapsed millis: " + elapsed);
+    }
+    
+    private void topMethod() {
+        aMethod();
+        bMethod();
+        cMethod();
+        dMethod(5);
+        
+        Thread t1 = new aThread();
+        t1.start();
+        Thread t2 = new aThread();
+        t2.start();
+        Thread t3 = new aThread();
+        t3.start();
+        try {
+            t1.join();
+            t2.join();
+            t3.join();
+        } catch (InterruptedException e) {
+        }
+    }
+    
+    private class aThread extends Thread {
+        @Override
+        public void run() {
+            aMethod();
+            bMethod();
+            cMethod();
+        }
+    }
+    
+    /** Calls other methods to make some interesting trace data.
+     * 
+     * @return a meaningless value
+     */
+    private int aMethod() {
+        int count = 0;
+        for (int ii = 0; ii < 6; ii++) {
+            count += bMethod();
+        }
+        for (int ii = 0; ii < 5; ii++) {
+            count += cMethod();
+        }
+        for (int ii = 0; ii < 4; ii++) {
+            count += dMethod(ii);
+        }
+        return count;
+    }
+    
+    /** Calls another method to make some interesting trace data.
+     * 
+     * @return a meaningless value
+     */
+    private int bMethod() {
+        int count = 0;
+        for (int ii = 0; ii < 4; ii++) {
+            count += cMethod();
+        }
+        return count;
+    }
+    
+    /** Executes a simple loop to make some interesting trace data.
+     * 
+     * @return a meaningless value
+     */
+    private int cMethod() {
+        int count = 0;
+        for (int ii = 0; ii < 1000; ii++) {
+            count += ii;
+        }
+        return count;
+    }
+    
+    /** Calls itself recursively to make some interesting trace data.
+     * 
+     * @return a meaningless value
+     */
+    private int dMethod(int level) {
+        int count = 0;
+        if (level > 0) {
+            count = dMethod(level - 1);
+        }
+        for (int ii = 0; ii < 100; ii++) {
+            count += ii;
+        }
+        if (level == 0) {
+            return count;
+        }
+        return dMethod(level - 1);
+    }
+    
+    public int eMethod() {
+        eMethodCalls += 1;
+        int count = fMethod();
+        count += gMethod(3);
+        return count;
+    }
+    
+    public int fMethod() {
+        fMethodCalls += 1;
+        int count = 0;
+        for (int ii = 0; ii < 10; ii++) {
+            count += ii;
+        }
+        return count;
+    }
+    
+    public int gMethod(int level) {
+        gMethodCalls += 1;
+        int count = level;
+        if (level > 1)
+            count += gMethod(level - 1);
+        return count;
+    }
+
+    /*
+     * This causes the native shared library to be loaded when the
+     * class is first used.  The library is only loaded once, even if
+     * multiple classes include this line.
+     *
+     * The library must be in java.library.path, which is derived from
+     * LD_LIBRARY_PATH.  The actual library name searched for will be
+     * "libtrace_test.so" under Linux, but may be different on other
+     * platforms.
+     */
+    static {
+        Log.i(TAG, "Loading trace_test native library...");
+        try {
+            System.loadLibrary("trace_test");
+            Log.i(TAG, "Successfully loaded trace_test native library");
+        }
+        catch (UnsatisfiedLinkError ule) {
+            Log.w(TAG, "Could not load trace_test native library");
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java b/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java
new file mode 100644
index 0000000..d77a819
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Implements basic performance test functionality for java.util.TreeMap
+ */
+
+public class TreeMapTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    public static TreeMap<String, Integer> sMap;
+    public static String[] sKeys;
+
+    @Override
+    @SuppressWarnings("unchecked")
+    protected void setUp() throws Exception {
+        super.setUp();
+        sMap = new TreeMap();
+        sKeys = new String[ITERATIONS];
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            sKeys[i] = Integer.toString(i, 16);
+            sMap.put(sKeys[i], i);
+        }
+    }
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testTreeMapPut() {
+        TreeMap map = new TreeMap();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            map.put(i, i);
+            map.put(i, i);
+            map.put(i, i);
+            map.put(i, i);
+            map.put(i, i);
+            map.put(i, i);
+            map.put(i, i);
+            map.put(i, i);
+            map.put(i, i);
+            map.put(i, i);
+        }
+    }
+
+    public void testTreeMapGet() {
+        int value;
+        TreeMap<String, Integer> map = sMap;
+        String[] keys = sKeys;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+            value = map.get(keys[i]);
+        }
+    }
+
+    public void testTreeMapFirstKey() {
+        String key;
+        TreeMap<String, Integer> map = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            key = map.firstKey();
+            key = map.firstKey();
+            key = map.firstKey();
+            key = map.firstKey();
+            key = map.firstKey();
+            key = map.firstKey();
+            key = map.firstKey();
+            key = map.firstKey();
+            key = map.firstKey();
+            key = map.firstKey();
+        }
+    }
+
+    public void testTreeMapKeySet() {
+        Set keyset;
+        TreeMap<String, Integer> map = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            keyset = map.keySet();
+            keyset = map.keySet();
+            keyset = map.keySet();
+            keyset = map.keySet();
+            keyset = map.keySet();
+            keyset = map.keySet();
+            keyset = map.keySet();
+            keyset = map.keySet();
+            keyset = map.keySet();
+            keyset = map.keySet();
+        }
+    }
+
+    public void testTreeMapEntrySet() {
+        Set keyset;
+        TreeMap<String, Integer> map = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+            keyset = map.entrySet();
+        }
+    }
+
+    public void testTreeMapValues() {
+        Collection collection;
+        TreeMap<String, Integer> map = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            collection = map.values();
+            collection = map.values();
+            collection = map.values();
+            collection = map.values();
+            collection = map.values();
+            collection = map.values();
+            collection = map.values();
+            collection = map.values();
+            collection = map.values();
+            collection = map.values();
+        }
+    }
+
+    public void testTreeMapSize() {
+        int len;
+        TreeMap<String, Integer> map = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            len = map.size();
+            len = map.size();
+            len = map.size();
+            len = map.size();
+            len = map.size();
+            len = map.size();
+            len = map.size();
+            len = map.size();
+            len = map.size();
+            len = map.size();
+        }
+    }
+
+    public void testTreeMapContainsKey() {
+        boolean flag;
+        String key = sKeys[525];
+        TreeMap<String, Integer> map = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+            flag = map.containsKey(key);
+        }
+    }
+
+    public void testTreeMapContainsValue() {
+        boolean flag;
+        TreeMap<String, Integer> map = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+            flag = map.containsValue(i);
+        }
+    }
+
+    public void testTreeMapHeadMap() {
+        SortedMap map;
+        String str = sKeys[100];
+        TreeMap<String, Integer> tMap = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+            map = tMap.headMap(str);
+        }
+    }
+
+    public void testTreeMapSubMap() {
+        String str1 = sKeys[400];
+        String str2 = sKeys[500];
+        SortedMap map;
+        TreeMap<String, Integer> tMap = sMap;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+            map = tMap.subMap(str1, str2);
+        }
+    }
+
+    public void testTreeMapTailMap() {
+        String str = sKeys[900];
+        TreeMap<String, Integer> tMap = sMap;
+        SortedMap map;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+            map = tMap.tailMap(str);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public void testTreeMapRemove() {
+        TreeMap<String, Integer> tMap = new TreeMap(sMap);
+        String[] keys = sKeys;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+            tMap.remove(keys[i]);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java b/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java
new file mode 100644
index 0000000..60dfe9a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+import java.util.TreeSet;
+import java.util.SortedSet;
+import java.util.Iterator;
+import java.util.Comparator;
+
+/**
+ * Implements basic performance test functionality for java.util.TreeSet
+ */
+
+public class TreeSetTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    public static TreeSet<Integer> sSet;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        sSet = new TreeSet<Integer>();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            sSet.add(i);
+        }
+    }
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    /**
+     * 
+     * Tests performance for the java.util.TreeSet method Add(Object arg 0)
+     * 
+     */
+
+    @SuppressWarnings("unchecked")
+    public void testTreeSetAdd() {
+        TreeSet<Integer> set = new TreeSet();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+            set.add(i);
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the java.util.TreeSet method - first()
+     * 
+     */
+
+    public void testTreeSetFirst() {
+        int value;
+        TreeSet<Integer> set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            value = set.first();
+            value = set.first();
+            value = set.first();
+            value = set.first();
+            value = set.first();
+            value = set.first();
+            value = set.first();
+            value = set.first();
+            value = set.first();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the java.util.TreeSet method - last()
+     * 
+     */
+
+    public void testTreeSetLast() {
+        int value;
+        TreeSet<Integer> set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            value = set.last();
+            value = set.last();
+            value = set.last();
+            value = set.last();
+            value = set.last();
+            value = set.last();
+            value = set.last();
+            value = set.last();
+            value = set.last();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance of the java.util.TreeSet method- contains(Object arg0)
+     * 
+     */
+
+    public void testTreeSetContains() {
+        Integer index = new Integer(500);
+        boolean flag;
+        TreeSet<Integer> set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+            flag = set.contains(index);
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the java.util.TreeSet method - size()
+     * 
+     */
+
+    public void testTreeSetSize() {
+        int value;
+        TreeSet<Integer> set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            value = set.size();
+            value = set.size();
+            value = set.size();
+            value = set.size();
+            value = set.size();
+            value = set.size();
+            value = set.size();
+            value = set.size();
+            value = set.size();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the java.util.TreeSet method - iterator()
+     * 
+     */
+
+    public void testTreeSetIterator() {
+        Iterator iterator;
+        TreeSet<Integer> set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+            iterator = set.iterator();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the java.util.TreeSet method - comparator()
+     * 
+     */
+
+    public void testTreeSetComparator() {
+        Comparator comparator;
+        TreeSet<Integer> set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            comparator = set.comparator();
+            comparator = set.comparator();
+            comparator = set.comparator();
+            comparator = set.comparator();
+            comparator = set.comparator();
+            comparator = set.comparator();
+            comparator = set.comparator();
+            comparator = set.comparator();
+            comparator = set.comparator();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the java.util.TreeSet method - clone()
+     * 
+     */
+
+    public void testTreeSetClone() {
+        Object obj;
+        TreeSet<Integer> set = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            obj = set.clone();
+            obj = set.clone();
+            obj = set.clone();
+            obj = set.clone();
+            obj = set.clone();
+            obj = set.clone();
+            obj = set.clone();
+            obj = set.clone();
+            obj = set.clone();
+            obj = set.clone();
+        }
+    }
+
+    /**
+     * 
+     * Tests performance of the java.util.TreeSet method - remove(Object arg0)
+     * 
+     */
+
+    @SuppressWarnings("unchecked")
+    public void testTreeSetRemove() {
+        TreeSet<Integer> set = new TreeSet(sSet);
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+            set.remove(i);
+        }
+    }
+
+    /**
+     * 
+     * Tests performance of the java.util.TreeSet method- headSet(Integer arg0)
+     * 
+     */
+
+    public void testTreeSetHeadSet() {
+        Integer value = new Integer(100);
+        SortedSet set;
+        TreeSet<Integer> tSet = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+            set = tSet.headSet(value);
+        }
+    }
+
+    /**
+     * 
+     * Tests performance of subSet(Integer arg0, Integer arg1) - TreeSet
+     * 
+     */
+
+    public void testTreeSetSubSet() {
+        Integer value = new Integer(400);
+        Integer nInt = new Integer(500);
+        SortedSet set;
+        TreeSet<Integer> tSet = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+            set = tSet.subSet(value, nInt);
+
+        }
+
+    }
+
+    /**
+     * 
+     * Tests performance of tailSet(Integer arg0) - TreeSet
+     * 
+     */
+
+    public void testTreeSetTailSet() {
+        Integer value = new Integer(900);
+        SortedSet set;
+        TreeSet<Integer> tSet = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+            set = tSet.tailSet(value);
+        }
+    }
+
+    /**
+     * 
+     * Tests performance for the java.util.TreeSet method - isEmpty()
+     * 
+     */
+
+    public void testTreeSetIsEmpty() {
+        boolean flag;
+        TreeSet<Integer> tSet = sSet;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+            flag = tSet.isEmpty();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java b/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java
new file mode 100644
index 0000000..ce3ea75
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.content.UriMatcher;
+import android.net.Uri;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+public class UriMatcherTest extends TestCase
+{
+    static final int ROOT = 0;
+    static final int PEOPLE = 1;
+    static final int PEOPLE_ID = 2;
+    static final int PEOPLE_PHONES = 3;
+    static final int PEOPLE_PHONES_ID = 4;
+    static final int PEOPLE_ADDRESSES = 5;
+    static final int PEOPLE_ADDRESSES_ID = 6;
+    static final int PEOPLE_CONTACTMETH = 7;
+    static final int PEOPLE_CONTACTMETH_ID = 8;
+    static final int CALLS = 9;
+    static final int CALLS_ID = 10;
+    static final int CALLERID = 11;
+    static final int CALLERID_TEXT = 12;
+    static final int FILTERRECENT = 13;
+    
+    @SmallTest
+    public void testContentUris() {
+        check("content://asdf", UriMatcher.NO_MATCH);
+        check("content://people", PEOPLE);
+        check("content://people/1", PEOPLE_ID);
+        check("content://people/asdf", UriMatcher.NO_MATCH);
+        check("content://people/2/phones", PEOPLE_PHONES); 
+        check("content://people/2/phones/3", PEOPLE_PHONES_ID); 
+        check("content://people/2/phones/asdf", UriMatcher.NO_MATCH);
+        check("content://people/2/addresses", PEOPLE_ADDRESSES); 
+        check("content://people/2/addresses/3", PEOPLE_ADDRESSES_ID); 
+        check("content://people/2/addresses/asdf", UriMatcher.NO_MATCH);
+        check("content://people/2/contact-methods", PEOPLE_CONTACTMETH); 
+        check("content://people/2/contact-methods/3", PEOPLE_CONTACTMETH_ID); 
+        check("content://people/2/contact-methods/asdf", UriMatcher.NO_MATCH);
+        check("content://calls", CALLS);
+        check("content://calls/1", CALLS_ID);
+        check("content://calls/asdf", UriMatcher.NO_MATCH);
+        check("content://caller-id", CALLERID);
+        check("content://caller-id/asdf", CALLERID_TEXT);
+        check("content://caller-id/1", CALLERID_TEXT);
+        check("content://filter-recent", FILTERRECENT);
+    }
+
+    private static final UriMatcher mURLMatcher = new UriMatcher(ROOT);
+
+    static
+    {
+        mURLMatcher.addURI("people", null, PEOPLE);
+        mURLMatcher.addURI("people", "#", PEOPLE_ID);
+        mURLMatcher.addURI("people", "#/phones", PEOPLE_PHONES);
+        mURLMatcher.addURI("people", "#/phones/blah", PEOPLE_PHONES_ID);
+        mURLMatcher.addURI("people", "#/phones/#", PEOPLE_PHONES_ID);
+        mURLMatcher.addURI("people", "#/addresses", PEOPLE_ADDRESSES);
+        mURLMatcher.addURI("people", "#/addresses/#", PEOPLE_ADDRESSES_ID);
+        mURLMatcher.addURI("people", "#/contact-methods", PEOPLE_CONTACTMETH);
+        mURLMatcher.addURI("people", "#/contact-methods/#", PEOPLE_CONTACTMETH_ID);
+        mURLMatcher.addURI("calls", null, CALLS);
+        mURLMatcher.addURI("calls", "#", CALLS_ID);
+        mURLMatcher.addURI("caller-id", null, CALLERID);
+        mURLMatcher.addURI("caller-id", "*", CALLERID_TEXT);
+        mURLMatcher.addURI("filter-recent", null, FILTERRECENT);
+    }
+
+    void check(String uri, int expected)
+    {
+        int result = mURLMatcher.match(Uri.parse(uri));
+        if (result != expected) {
+            String msg = "failed on " + uri;
+            msg += " expected " + expected + " got " + result;
+            throw new RuntimeException(msg);
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/UriTest.java b/tests/AndroidTests/src/com/android/unit_tests/UriTest.java
new file mode 100644
index 0000000..130beeb
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/UriTest.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.net.Uri;
+import android.content.ContentUris;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.Arrays;
+
+public class UriTest extends TestCase {
+
+    @SmallTest
+    public void testToStringWithPathOnly() {
+        Uri.Builder builder = new Uri.Builder();
+
+        // Not a valid path, but this came from a user's test case.
+        builder.path("//foo");
+        Uri uri = builder.build();
+        assertEquals("//foo", uri.toString());
+    }
+
+    @SmallTest
+    public void testParcelling() {
+        parcelAndUnparcel(Uri.parse("foo:bob%20lee"));
+        parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment"));
+        parcelAndUnparcel(new Uri.Builder()
+            .scheme("http")
+            .authority("crazybob.org")
+            .path("/rss/")
+            .encodedQuery("a=b")
+            .fragment("foo")
+            .build());
+    }
+
+    private void parcelAndUnparcel(Uri u) {
+        Parcel p = Parcel.obtain();
+        Uri.writeToParcel(p, u);
+        p.setDataPosition(0);
+        assertEquals(u, Uri.CREATOR.createFromParcel(p));
+
+        p.setDataPosition(0);
+        u = u.buildUpon().build();        
+        Uri.writeToParcel(p, u);
+        p.setDataPosition(0);
+        assertEquals(u, Uri.CREATOR.createFromParcel(p));
+    }
+
+    @SmallTest
+    public void testBuildUponOpaqueStringUri() {
+        Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build();
+        assertEquals("robert", u.getScheme());
+        assertEquals("lee", u.getEncodedSchemeSpecificPart());
+        assertEquals("lee", u.getSchemeSpecificPart());
+        assertNull(u.getQuery());
+        assertNull(u.getPath());
+        assertNull(u.getAuthority());
+        assertNull(u.getHost());
+    }
+
+    @SmallTest
+    public void testStringUri() {
+        assertEquals("bob lee",
+                Uri.parse("foo:bob%20lee").getSchemeSpecificPart());
+        assertEquals("bob%20lee",
+                Uri.parse("foo:bob%20lee").getEncodedSchemeSpecificPart());
+        assertEquals("/bob%20lee",
+                Uri.parse("foo:/bob%20lee").getEncodedPath());
+        assertNull(Uri.parse("foo:bob%20lee").getPath());
+        assertEquals("bob%20lee",
+                Uri.parse("foo:?bob%20lee").getEncodedQuery());
+        assertNull(Uri.parse("foo:bar#?bob%20lee").getQuery());
+        assertEquals("bob%20lee",
+                Uri.parse("foo:#bob%20lee").getEncodedFragment());
+    }
+
+    @SmallTest
+    public void testStringUriIsHierarchical() {
+        assertTrue(Uri.parse("bob").isHierarchical());
+        assertFalse(Uri.parse("bob:").isHierarchical());
+    }
+
+    @SmallTest
+    public void testNullUriString() {
+        try {
+            Uri.parse(null);
+            fail();
+        } catch (NullPointerException e) {}
+    }
+
+    @SmallTest
+    public void testNullFile() {
+        try {
+            Uri.fromFile(null);
+            fail();
+        } catch (NullPointerException e) {}
+    }
+
+    @SmallTest
+    public void testCompareTo() {
+        Uri a = Uri.parse("foo:a");
+        Uri b = Uri.parse("foo:b");
+        Uri b2 = Uri.parse("foo:b");
+
+        assertTrue(a.compareTo(b) < 0);
+        assertTrue(b.compareTo(a) > 0);
+        assertEquals(0, b.compareTo(b2));
+    }
+
+    @SmallTest
+    public void testEqualsAndHashCode() {
+
+        Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee");
+
+        Uri b = new Uri.Builder()
+                .scheme("http")
+                .authority("crazybob.org")
+                .path("/test/")
+                .encodedQuery("foo=bar")
+                .fragment("tee")
+                .build();
+
+        // Try alternate builder methods.
+        Uri c = new Uri.Builder()
+                .scheme("http")
+                .encodedAuthority("crazybob.org")
+                .encodedPath("/test/")
+                .encodedQuery("foo=bar")
+                .encodedFragment("tee")
+                .build();
+
+        assertFalse(Uri.EMPTY.equals(null));
+
+        assertEquals(a, b);
+        assertEquals(b, c);
+        assertEquals(c, a);
+
+        assertEquals(a.hashCode(), b.hashCode());
+        assertEquals(b.hashCode(), c.hashCode());
+    }
+
+    @SmallTest
+    public void testAuthorityParsing() {
+        Uri uri = Uri.parse("http://localhost:42");
+        assertEquals("localhost", uri.getHost());
+        assertEquals(42, uri.getPort());
+
+        uri = Uri.parse("http://bob@localhost:42");
+        assertEquals("bob", uri.getUserInfo());
+        assertEquals("localhost", uri.getHost());
+        assertEquals(42, uri.getPort());
+
+        uri = Uri.parse("http://bob%20lee@localhost:42");
+        assertEquals("bob lee", uri.getUserInfo());
+        assertEquals("bob%20lee", uri.getEncodedUserInfo());
+
+        uri = Uri.parse("http://localhost");
+        assertEquals("localhost", uri.getHost());
+        assertEquals(-1, uri.getPort());
+    }
+
+    @SmallTest
+    public void testBuildUponOpaqueUri() {
+        Uri a = Uri.fromParts("foo", "bar", "tee");
+        Uri b = a.buildUpon().fragment("new").build();
+        assertEquals("new", b.getFragment());
+        assertEquals("bar", b.getSchemeSpecificPart());
+        assertEquals("foo", b.getScheme());        
+    }
+
+    @SmallTest
+    public void testBuildUponEncodedOpaqueUri() {
+        Uri a = new Uri.Builder()
+                .scheme("foo")
+                .encodedOpaquePart("bar")
+                .fragment("tee")
+                .build();
+        Uri b = a.buildUpon().fragment("new").build();
+        assertEquals("new", b.getFragment());
+        assertEquals("bar", b.getSchemeSpecificPart());
+        assertEquals("foo", b.getScheme());
+    }
+
+    @SmallTest
+    public void testPathSegmentDecoding() {
+        Uri uri = Uri.parse("foo://bar/a%20a/b%20b");
+        assertEquals("a a", uri.getPathSegments().get(0));
+        assertEquals("b b", uri.getPathSegments().get(1));
+    }
+
+    @SmallTest
+    public void testSms() {
+        Uri base = Uri.parse("content://sms");
+        Uri appended = base.buildUpon()
+                .appendEncodedPath("conversations/addr=555-1212")
+                .build();
+        assertEquals("content://sms/conversations/addr=555-1212",
+                appended.toString());
+        assertEquals(2, appended.getPathSegments().size());
+        assertEquals("conversations", appended.getPathSegments().get(0));
+        assertEquals("addr=555-1212", appended.getPathSegments().get(1));
+    }
+
+    @SmallTest
+    public void testEncodeWithAllowedChars() {
+        String encoded = Uri.encode("Bob:/", "/");
+        assertEquals(-1, encoded.indexOf(':'));
+        assertTrue(encoded.indexOf('/') > -1);
+    }
+
+    @SmallTest
+    public void testEncodeDecode() {
+        code(null);
+        code("");
+        code("Bob");
+        code(":Bob");
+        code("::Bob");
+        code("Bob::Lee");
+        code("Bob:Lee");
+        code("Bob::");
+        code("Bob:");
+        code("::Bob::");
+    }
+
+    private void code(String s) {
+        assertEquals(s, Uri.decode(Uri.encode(s, null)));
+    }
+
+    @SmallTest
+    public void testFile() {
+        File f = new File("/tmp/bob");
+
+        Uri uri = Uri.fromFile(f);
+
+        assertEquals("file:///tmp/bob", uri.toString());
+    }
+
+    @SmallTest
+    public void testQueryParameters() {
+        Uri uri = Uri.parse("content://user");
+
+        assertEquals(null, uri.getQueryParameter("a"));
+
+        uri = uri.buildUpon().appendQueryParameter("a", "b").build();
+
+        assertEquals("b", uri.getQueryParameter("a"));
+
+        uri = uri.buildUpon().appendQueryParameter("a", "b2").build();
+
+        assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a"));
+
+        uri = uri.buildUpon().appendQueryParameter("c", "d").build();
+
+        assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a"));
+        assertEquals("d", uri.getQueryParameter("c"));
+    }
+
+    @SmallTest
+    public void testSchemeOnly() {
+        Uri uri = Uri.parse("empty:");
+        assertEquals("empty", uri.getScheme());
+        assertTrue(uri.isAbsolute());
+        assertNull(uri.getPath());
+    }
+
+    @SmallTest
+    public void testEmptyPath() {
+        Uri uri = Uri.parse("content://user");
+        assertEquals(0, uri.getPathSegments().size());
+    }
+
+    @SmallTest
+    public void testPathOperations() {
+        Uri uri = Uri.parse("content://user/a/b");
+
+        assertEquals(2, uri.getPathSegments().size());
+        assertEquals("b", uri.getLastPathSegment());
+
+        Uri first = uri;
+        uri = uri.buildUpon().appendPath("c").build();
+
+        assertEquals(3, uri.getPathSegments().size());
+        assertEquals("c", uri.getLastPathSegment());
+        assertEquals("content://user/a/b/c", uri.toString());
+
+        uri = ContentUris.withAppendedId(uri, 100);
+
+        assertEquals(4, uri.getPathSegments().size());
+        assertEquals("100", uri.getLastPathSegment());
+        assertEquals(100, ContentUris.parseId(uri));
+        assertEquals("content://user/a/b/c/100", uri.toString());
+
+        // Make sure the original URI is still intact.
+        assertEquals(2, first.getPathSegments().size());
+        assertEquals("b", first.getLastPathSegment());
+
+        try {
+            first.getPathSegments().get(2);
+            fail();
+        } catch (IndexOutOfBoundsException e) {}
+
+        assertEquals(null, Uri.EMPTY.getLastPathSegment());
+
+        Uri withC = Uri.parse("foo:/a/b/").buildUpon().appendPath("c").build();
+        assertEquals("/a/b/c", withC.getPath());
+    }
+
+    @SmallTest
+    public void testOpaqueUri() {
+        Uri uri = Uri.parse("mailto:nobody");
+        testOpaqueUri(uri);
+
+        uri = uri.buildUpon().build();
+        testOpaqueUri(uri);
+
+        uri = Uri.fromParts("mailto", "nobody", null);
+        testOpaqueUri(uri);
+
+        uri = uri.buildUpon().build();
+        testOpaqueUri(uri);
+
+        uri = new Uri.Builder()
+                .scheme("mailto")
+                .opaquePart("nobody")
+                .build();
+        testOpaqueUri(uri);
+
+        uri = uri.buildUpon().build();
+        testOpaqueUri(uri);
+    }
+
+    private void testOpaqueUri(Uri uri) {
+        assertEquals("mailto", uri.getScheme());
+        assertEquals("nobody", uri.getSchemeSpecificPart());
+        assertEquals("nobody", uri.getEncodedSchemeSpecificPart());
+
+        assertNull(uri.getFragment());
+        assertTrue(uri.isAbsolute());
+        assertTrue(uri.isOpaque());
+        assertFalse(uri.isRelative());
+        assertFalse(uri.isHierarchical());
+
+        assertNull(uri.getAuthority());
+        assertNull(uri.getEncodedAuthority());
+        assertNull(uri.getPath());
+        assertNull(uri.getEncodedPath());
+        assertNull(uri.getUserInfo());
+        assertNull(uri.getEncodedUserInfo());
+        assertNull(uri.getQuery());
+        assertNull(uri.getEncodedQuery());
+        assertNull(uri.getHost());
+        assertEquals(-1, uri.getPort());
+
+        assertTrue(uri.getPathSegments().isEmpty());
+        assertNull(uri.getLastPathSegment());
+
+        assertEquals("mailto:nobody", uri.toString());
+
+        Uri withFragment = uri.buildUpon().fragment("top").build();
+        assertEquals("mailto:nobody#top", withFragment.toString());
+    }
+
+    @SmallTest
+    public void testHierarchicalUris() {
+        testHierarchical("http", "google.com", "/p1/p2", "query", "fragment");
+        testHierarchical("file", null, "/p1/p2", null, null);
+        testHierarchical("content", "contact", "/p1/p2", null, null);
+        testHierarchical("http", "google.com", "/p1/p2", null, "fragment");
+        testHierarchical("http", "google.com", "", null, "fragment");
+        testHierarchical("http", "google.com", "", "query", "fragment");
+        testHierarchical("http", "google.com", "", "query", null);
+        testHierarchical("http", null, "/", "query", null);
+    }
+
+    private static void testHierarchical(String scheme, String authority,
+            String path, String query, String fragment) {
+        StringBuilder sb = new StringBuilder();
+
+        if (authority != null) {
+            sb.append("//").append(authority);
+        }
+        if (path != null) {
+            sb.append(path);
+        }
+        if (query != null) {
+            sb.append('?').append(query);
+        }
+
+        String ssp = sb.toString();
+
+        if (scheme != null) {
+            sb.insert(0, scheme + ":");
+        }
+        if (fragment != null) {
+            sb.append('#').append(fragment);
+        }
+
+        String uriString = sb.toString();
+
+        Uri uri = Uri.parse(uriString);
+
+        // Run these twice to test caching.
+        compareHierarchical(
+                uriString, ssp, uri, scheme, authority, path, query, fragment);
+        compareHierarchical(
+                uriString, ssp, uri, scheme, authority, path, query, fragment);
+
+        // Test rebuilt version.
+        uri = uri.buildUpon().build();
+
+        // Run these twice to test caching.
+        compareHierarchical(
+                uriString, ssp, uri, scheme, authority, path, query, fragment);
+        compareHierarchical(
+                uriString, ssp, uri, scheme, authority, path, query, fragment);
+
+        // The decoded and encoded versions of the inputs are all the same.
+        // We'll test the actual encoding decoding separately.
+
+        // Test building with encoded versions.
+        Uri built = new Uri.Builder()
+                .scheme(scheme)
+                .encodedAuthority(authority)
+                .encodedPath(path)
+                .encodedQuery(query)
+                .encodedFragment(fragment)
+                .build();
+
+        compareHierarchical(
+                uriString, ssp, built, scheme, authority, path, query, fragment);
+        compareHierarchical(
+                uriString, ssp, built, scheme, authority, path, query, fragment);
+
+        // Test building with decoded versions.
+        built = new Uri.Builder()
+                .scheme(scheme)
+                .authority(authority)
+                .path(path)
+                .query(query)
+                .fragment(fragment)
+                .build();
+
+        compareHierarchical(
+                uriString, ssp, built, scheme, authority, path, query, fragment);
+        compareHierarchical(
+                uriString, ssp, built, scheme, authority, path, query, fragment);
+
+        // Rebuild.
+        built = built.buildUpon().build();
+
+        compareHierarchical(
+                uriString, ssp, built, scheme, authority, path, query, fragment);
+        compareHierarchical(
+                uriString, ssp, built, scheme, authority, path, query, fragment);
+    }
+
+    private static void compareHierarchical(String uriString, String ssp,
+            Uri uri,
+            String scheme, String authority, String path, String query,
+            String fragment) {
+        assertEquals(scheme, uri.getScheme());
+        assertEquals(authority, uri.getAuthority());
+        assertEquals(authority, uri.getEncodedAuthority());
+        assertEquals(path, uri.getPath());
+        assertEquals(path, uri.getEncodedPath());
+        assertEquals(query, uri.getQuery());
+        assertEquals(query, uri.getEncodedQuery());
+        assertEquals(fragment, uri.getFragment());
+        assertEquals(fragment, uri.getEncodedFragment());
+        assertEquals(ssp, uri.getSchemeSpecificPart());
+
+        if (scheme != null) {
+            assertTrue(uri.isAbsolute());
+            assertFalse(uri.isRelative());
+        } else {
+            assertFalse(uri.isAbsolute());
+            assertTrue(uri.isRelative());
+        }
+
+        assertFalse(uri.isOpaque());
+        assertTrue(uri.isHierarchical());
+
+        assertEquals(uriString, uri.toString());
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java b/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java
new file mode 100644
index 0000000..a7c19a7
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2008 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.unit_tests;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.google.android.net.UrlRules;
+import static com.google.android.net.UrlRules.Rule;
+
+/** Test loading and matching URL rewrite rules for UrlRules.  */
+public class UrlRulesTest extends AndroidTestCase {
+    @SmallTest
+    public void testEmptyRules() {
+        UrlRules rules = new UrlRules(new Rule[] { });
+        assertTrue(rules.matchRule("http://foo.bar/") == Rule.DEFAULT);
+    }
+
+    @SmallTest
+    public void testInvalidRule() throws Exception {
+        try {
+            new Rule("rule", "foo bar");
+        } catch (Exception e) {
+            // Re-throw any exception except the one we're looking for.
+            if (!e.toString().contains("Illegal rule: foo bar")) throw e;
+        }
+    }
+
+    @SmallTest
+    public void testRewriteRule() throws UrlRules.RuleFormatException {
+        Rule rule = new Rule("test_rule",
+                "http://foo.bar/ rewrite http://bar.foo/");
+        assertEquals("test_rule", rule.mName);
+        assertEquals("http://foo.bar/", rule.mPrefix);
+        assertEquals("http://bar.foo/", rule.mRewrite);
+        assertFalse(rule.mBlock);
+        assertEquals("http://bar.foo/bat", rule.apply("http://foo.bar/bat"));
+    }
+
+    @SmallTest
+    public void testBlockRule() throws UrlRules.RuleFormatException {
+        Rule rule = new Rule("test_rule",
+                "http://foo.bar/ block");
+        assertEquals("test_rule", rule.mName);
+        assertEquals("http://foo.bar/", rule.mPrefix);
+        assertTrue(rule.mRewrite == null);
+        assertTrue(rule.mBlock);
+        assertTrue(rule.apply("http://foo.bar/bat") == null);
+    }
+
+    @SmallTest
+    public void testMatchRule() throws UrlRules.RuleFormatException {
+        UrlRules rules = new UrlRules(new Rule[] {
+            new Rule("12", "http://one.two/ rewrite http://buckle.my.shoe/"),
+            new Rule("34", "http://three.four/ rewrite http://close.the.door/"),
+            new Rule("56", "http://five.six/ rewrite http://pick.up.sticks/"),
+        });
+
+        assertTrue(rules.matchRule("https://one.two/") == Rule.DEFAULT);
+        assertTrue(rules.matchRule("http://one.two") == Rule.DEFAULT);
+        assertEquals("12", rules.matchRule("http://one.two/foo").mName);
+
+        String u = "http://five.six/bar";
+        assertEquals("http://pick.up.sticks/bar", rules.matchRule(u).apply(u));
+    }
+
+    @SmallTest
+    public void testAmbiguousMatch() throws UrlRules.RuleFormatException {
+        // Rule is the longest match wins.
+        UrlRules rules = new UrlRules(new Rule[] {
+            new Rule("1", "http://xyz/one rewrite http://rewrite/"),
+            new Rule("123", "http://xyz/onetwothree rewrite http://rewrite/"),
+            new Rule("12", "http://xyz/onetwo rewrite http://rewrite/"),
+        });
+
+        assertEquals("1", rules.matchRule("http://xyz/one").mName);
+        assertEquals("1", rules.matchRule("http://xyz/one...").mName);
+        assertEquals("12", rules.matchRule("http://xyz/onetwo...").mName);
+        assertEquals("123", rules.matchRule("http://xyz/onetwothree...").mName);
+
+    }
+
+    @MediumTest
+    public void testGservicesRules() {
+        // TODO: use a MockContentProvider/MockContentResolver instead.
+        ContentResolver r = getContext().getContentResolver();
+
+        // Update the digest, so the UrlRules cache is reloaded.
+        Settings.Gservices.putString(r, "digest", "testGservicesRules");
+        Settings.Gservices.putString(r, "url:blank_test", "");
+        Settings.Gservices.putString(r, "url:test",
+                "http://foo.bar/ rewrite http://bar.foo/");
+
+        UrlRules rules = UrlRules.getRules(r);  // Don't crash, please.  :)
+        assertTrue(rules.matchRule("http://bar.foo/") == Rule.DEFAULT);
+
+        Rule rule = rules.matchRule("http://foo.bar/bat");
+        assertEquals("test", rule.mName);
+        assertEquals("http://foo.bar/", rule.mPrefix);
+        assertEquals("http://bar.foo/", rule.mRewrite);
+        assertFalse(rule.mBlock);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java b/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java
new file mode 100644
index 0000000..22f9771
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2007 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.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * Basic Performance Tests for java.util.Vector
+ */
+
+@SuppressWarnings("unchecked")
+public class VectorTest extends PerformanceTestBase {
+    public static final int ITERATIONS = 1000;
+    private Vector<Integer> mVector;
+    private Vector<String> mStrVector;
+    private String mTestString = "Hello Android";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mVector = new Vector();
+        mStrVector = new Vector();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            assertTrue(mVector.add(i));
+            assertTrue(mStrVector.add(Integer.toString(i)));
+        }
+    }
+
+    @Override
+    public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+        intermediates.setInternalIterations(ITERATIONS);
+        return 0;
+    }
+
+    public void testVectorAdd() {
+        Vector<Integer> vector = new Vector();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            vector.add(i);
+            vector.add(i);
+            vector.add(i);
+            vector.add(i);
+            vector.add(i);
+            vector.add(i);
+            vector.add(i);
+            vector.add(i);
+            vector.add(i);
+            vector.add(i);
+        }
+    }
+
+    public void testVectorAdd1() {
+        Vector<Integer> vector = new Vector();
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            vector.add(0, i);
+            vector.add(0, i);
+            vector.add(0, i);
+            vector.add(0, i);
+            vector.add(0, i);
+            vector.add(0, i);
+            vector.add(0, i);
+            vector.add(0, i);
+            vector.add(0, i);
+            vector.add(0, i);
+        }
+    }
+
+    public void testVectorToArray() {
+        Object array;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            array = vector.toArray();
+            array = vector.toArray();
+            array = vector.toArray();
+            array = vector.toArray();
+            array = vector.toArray();
+            array = vector.toArray();
+            array = vector.toArray();
+            array = vector.toArray();
+            array = vector.toArray();
+            array = vector.toArray();
+        }
+    }
+
+    /**
+     * 
+     */
+    public void testVectorSize() {
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            int mLen;
+            mLen = vector.size();
+            mLen = vector.size();
+            mLen = vector.size();
+            mLen = vector.size();
+            mLen = vector.size();
+            mLen = vector.size();
+            mLen = vector.size();
+            mLen = vector.size();
+            mLen = vector.size();
+            mLen = vector.size();
+        }
+    }
+
+    public void testVectorGet() {
+        int element;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            element = vector.get(i);
+            element = vector.get(i);
+            element = vector.get(i);
+            element = vector.get(i);
+            element = vector.get(i);
+            element = vector.get(i);
+            element = vector.get(i);
+            element = vector.get(i);
+            element = vector.get(i);
+            element = vector.get(i);
+        }
+
+    }
+
+    public void testVectorContains() {
+        boolean flag;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+            flag = vector.contains(i);
+        }
+    }
+
+    public void testVectorToArray1() {
+        Integer[] rArray = new Integer[100];
+        Integer[] array;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+            array = vector.toArray(rArray);
+        }
+    }
+
+    public void testVectorSet() {
+        Vector<Integer> vector = mVector;
+        int pos = 5, value = 0;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            vector.set(pos, value);
+            vector.set(pos, value);
+            vector.set(pos, value);
+            vector.set(pos, value);
+            vector.set(pos, value);
+            vector.set(pos, value);
+            vector.set(pos, value);
+            vector.set(pos, value);
+            vector.set(pos, value);
+            vector.set(pos, value);
+        }
+    }
+
+    public void testVectorIndexOf() {
+        int index, value = 0;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+            index = vector.indexOf(value);
+        }
+    }
+
+    public void testVectorLastIndexOf() {
+        int index, value = 0;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i >= 0; i--) {
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+            index = vector.lastIndexOf(value);
+        }
+    }
+
+    public void testVectorRemove() {
+        int index, value = 0;
+        Vector<Integer> vector = new Vector(mVector);
+        for (int i = 10; i > 0; i--) {
+            index = vector.remove(value);
+            index = vector.remove(value);
+            index = vector.remove(value);
+            index = vector.remove(value);
+            index = vector.remove(value);
+            index = vector.remove(value);
+            index = vector.remove(value);
+            index = vector.remove(value);
+            index = vector.remove(value);
+            index = vector.remove(value);
+        }
+    }
+
+    public void testVectorRemoveElement() {
+        Vector<Integer> vector = new Vector(mVector);
+        for (int i = 10; i > 0; i--) {
+            vector.removeElement(i);
+            vector.removeElement(i);
+            vector.removeElement(i);
+            vector.removeElement(i);
+            vector.removeElement(i);
+            vector.removeElement(i);
+            vector.removeElement(i);
+            vector.removeElement(i);
+            vector.removeElement(i);
+            vector.removeElement(i);
+        }
+    }
+
+    public void VectorRemoveElementAt() {
+        Vector<Integer> vector = new Vector(mVector);
+        for (int i = 10; i > 0; i--) {
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+            vector.removeElementAt(i);
+        }
+    }
+
+    public void VectorAddAll() {
+        Vector<Integer> vector = new Vector(), vector1 = mVector;
+
+        boolean flag;
+        for (int i = 10; i > 0; i--) {
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+            flag = vector.addAll(vector1);
+        }
+    }
+
+    public void VectorRemove1() {
+        Vector<String> vector = mStrVector;
+        for (int j = 1000; j > 0; j--) {
+            vector.add("a");
+            vector.add("b");
+        }
+        String s = new String("a");
+        boolean flag;
+        for (int i = 10; i > 0; i--) {
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+            flag = vector.remove(s);
+        }
+    }
+
+    public void testVectorAddAll1() {
+        Vector<Integer> mEmptyVector = new Vector();
+        boolean flag;
+        int pos = 0;
+        Vector<Integer> vector1 = mVector;
+        Vector<Integer> vector = mEmptyVector;
+        for (int i = 10; i > 0; i--) {
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+            flag = vector.addAll(pos, vector1);
+        }
+    }
+
+    public void testVectorClone() {
+        Object obj;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            obj = vector.clone();
+            obj = vector.clone();
+            obj = vector.clone();
+            obj = vector.clone();
+            obj = vector.clone();
+            obj = vector.clone();
+            obj = vector.clone();
+            obj = vector.clone();
+            obj = vector.clone();
+            obj = vector.clone();
+        }
+    }
+
+    public void testVectorCapacity() {
+        int capacity;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+            capacity = vector.capacity();
+        }
+    }
+
+    public void testVectorHashcode() {
+        int element;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            element = vector.hashCode();
+            element = vector.hashCode();
+            element = vector.hashCode();
+            element = vector.hashCode();
+            element = vector.hashCode();
+            element = vector.hashCode();
+            element = vector.hashCode();
+            element = vector.hashCode();
+            element = vector.hashCode();
+            element = vector.hashCode();
+        }
+    }
+
+    public void testVectorElements() {
+        Enumeration<Integer> elements;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            elements = vector.elements();
+            elements = vector.elements();
+            elements = vector.elements();
+            elements = vector.elements();
+            elements = vector.elements();
+            elements = vector.elements();
+            elements = vector.elements();
+            elements = vector.elements();
+            elements = vector.elements();
+            elements = vector.elements();
+        }
+    }
+
+    public void testVectorToString() {
+        String str;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            str = vector.toString();
+            str = vector.toString();
+            str = vector.toString();
+            str = vector.toString();
+            str = vector.toString();
+            str = vector.toString();
+            str = vector.toString();
+            str = vector.toString();
+            str = vector.toString();
+            str = vector.toString();
+        }
+    }
+
+    public void testVectorElementAt() {
+        int element;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+            element = vector.elementAt(50);
+        }
+    }
+
+    public void testVectorAddElement() {
+        int element;
+        Vector<String> vector = mStrVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+            vector.addElement(mTestString);
+        }
+    }
+
+    public void testVectorFirstElement() {
+        int element;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            element = vector.firstElement();
+            element = vector.firstElement();
+            element = vector.firstElement();
+            element = vector.firstElement();
+            element = vector.firstElement();
+            element = vector.firstElement();
+            element = vector.firstElement();
+            element = vector.firstElement();
+            element = vector.firstElement();
+            element = vector.firstElement();
+        }
+    }
+
+    public void testVectorLastElement() {
+        int element;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            element = vector.lastElement();
+            element = vector.lastElement();
+            element = vector.lastElement();
+            element = vector.lastElement();
+            element = vector.lastElement();
+            element = vector.lastElement();
+            element = vector.lastElement();
+            element = vector.lastElement();
+            element = vector.lastElement();
+            element = vector.lastElement();
+        }
+    }
+
+    public void testVectorSetElementAt() {
+        Vector<Integer> vector = mVector;
+        int value1 = 500, value2 = 50;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+            vector.setElementAt(value1, value2);
+        }
+    }
+
+    public void testVectorIsEmpty() {
+        boolean flag;
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+            flag = vector.isEmpty();
+        }
+    }
+
+    public void testVectorCopyInto() {
+        Integer[] rArray = new Integer[ITERATIONS];
+        Vector<Integer> vector = mVector;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+            vector.copyInto(rArray);
+        }
+    }
+
+    public void testVectorInsertElementAt() {
+        Vector<String> vector = mStrVector;
+        String string = mTestString;
+        for (int i = ITERATIONS - 1; i > 0; i--) {
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+            vector.insertElementAt(string, i);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java b/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java
new file mode 100644
index 0000000..4a0519e
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.AndroidTestCase;
+import android.text.format.DateFormat;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import android.webkit.DateSorter;
+
+import java.util.Calendar;
+import java.util.Date;
+
+public class WebkitTest extends AndroidTestCase {
+
+    private static final String LOGTAG = WebkitTest.class.getName();
+
+    @MediumTest
+    public void testDateSorter() throws Exception {
+        /**
+         * Note: check the logging output manually to test
+         * nothing automated yet, besides object creation
+         */
+        DateSorter dateSorter = new DateSorter(mContext);
+        Date date = new Date();
+
+        for (int i = 0; i < DateSorter.DAY_COUNT; i++) {
+            Log.i(LOGTAG, "Boundary " + i + " " + dateSorter.getBoundary(i));
+            Log.i(LOGTAG, "Label " + i + " " + dateSorter.getLabel(i));
+        }
+
+        Calendar c = Calendar.getInstance();
+        long time = c.getTimeInMillis();
+        int index;
+        Log.i(LOGTAG, "now: " + dateSorter.getIndex(time));
+        for (int i = 0; i < 20; i++) {
+            time -= 8 * 60 * 60 * 1000; // 8 hours
+            date.setTime(time);
+            c.setTime(date);
+            index = dateSorter.getIndex(time);
+            Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd kk:mm:ss", c).toString() +
+                    " " + index + " " + dateSorter.getLabel(index));
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java
new file mode 100644
index 0000000..d9d6101
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.util.Log;
+
+public class AbortReceiver extends BroadcastReceiver
+{
+    public AbortReceiver()
+    {
+    }
+
+    public void onReceive(Context context, Intent intent)
+    {
+	//Log.i("AbortReceiver", "onReceiveIntent!");
+        try {
+            IBinder caller = intent.getIBinderExtra("caller");
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+            data.writeString(LaunchpadActivity.RECEIVER_ABORT);
+            caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0);
+            data.recycle();
+        } catch (RemoteException ex) {
+        }
+        
+        // abort the broadcast!!!
+        abortBroadcast();
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java
new file mode 100644
index 0000000..ab91761
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.activity;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.content.res.Configuration;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import java.util.Iterator;
+import java.util.List;
+
+public class ActivityManagerTest extends AndroidTestCase {
+
+    protected Context mContext;
+    protected ActivityManager mActivityManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getContext();
+        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+    }
+
+    // TODO should write a test for getRecentTasks()
+    // TODO should write a test for getRunningTasks()
+    // TODO should write a test for getMemoryInfo()
+    
+    // TODO: Find a way to re-enable this.  It fails if any other app has failed during startup.
+    // This is probably an OK assumption given the desired system status when we run unit tests,
+    // but it's not necessarily the right assumption for a unit test.
+    @Suppress
+    public void disabledTestErrorTasksEmpty() throws Exception {
+        
+        List<ActivityManager.ProcessErrorStateInfo> errList;
+        
+        errList = mActivityManager.getProcessesInErrorState();
+        
+        // test: confirm list is empty
+        assertNull(errList);
+    }
+    
+    // TODO: Force an activity into an error state - then see if we can catch it here?
+    @SmallTest
+    public void testErrorTasksWithError() throws Exception {
+        
+        List<ActivityManager.ProcessErrorStateInfo> errList;
+        
+        // TODO force another process into an error condition.  How?
+        
+        // test: confirm error list length is at least 1 under varying query lengths
+//      checkErrorListMax(1,-1);
+
+        errList = mActivityManager.getProcessesInErrorState();
+
+        // test: the list itself is healthy
+        checkErrorListSanity(errList);
+
+        // test: confirm our application shows up in the list
+    }
+    
+    // TODO: Force an activity into an ANR state - then see if we can catch it here?
+    @SmallTest
+    public void testErrorTasksWithANR() throws Exception {
+        
+        List<ActivityManager.ProcessErrorStateInfo> errList;
+        
+        // TODO: force an application into an ANR state
+        
+        errList = mActivityManager.getProcessesInErrorState();
+
+        // test: the list itself is healthy
+        checkErrorListSanity(errList);
+
+        // test: confirm our ANR'ing application shows up in the list
+    }
+    
+    @SmallTest
+    public void testGetDeviceConfigurationInfo() throws Exception {
+        ConfigurationInfo config = mActivityManager.getDeviceConfigurationInfo();
+        assertNotNull(config);
+        // Validate values against configuration retrieved from resources
+        Configuration vconfig = mContext.getResources().getConfiguration();
+        assertNotNull(vconfig);
+        assertEquals(config.reqKeyboardType, vconfig.keyboard);
+        assertEquals(config.reqTouchScreen, vconfig.touchscreen);
+        assertEquals(config.reqNavigation, vconfig.navigation);
+        if (vconfig.navigation == Configuration.NAVIGATION_NONAV) {
+            assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV);
+        }
+        if (vconfig.keyboard != Configuration.KEYBOARD_UNDEFINED) {
+            assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD);
+        }    
+    }
+    
+    // If any entries in appear in the list, sanity check them against all running applications
+    private void checkErrorListSanity(List<ActivityManager.ProcessErrorStateInfo> errList) {
+        if (errList == null) return;
+        
+        Iterator<ActivityManager.ProcessErrorStateInfo> iter = errList.iterator();
+        while (iter.hasNext()) {
+            ActivityManager.ProcessErrorStateInfo info = iter.next();
+            assertNotNull(info);
+            // sanity checks
+            assertTrue((info.condition == ActivityManager.ProcessErrorStateInfo.CRASHED) ||
+                       (info.condition == ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING));
+            // TODO look at each of these and consider a stronger test
+            // TODO can we cross-check at the process name via some other API?
+            // TODO is there a better test for strings, e.g. "assertIsLegalString")
+            assertNotNull(info.processName);
+            // reasonableness test for info.pid ?
+            assertNotNull(info.longMsg);
+            assertNotNull(info.shortMsg);
+            // is there any reasonable test for the crashData?  Probably not. 
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java
new file mode 100644
index 0000000..cffc60a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import junit.framework.TestSuite;
+
+public class ActivityTests {
+    public static final boolean DEBUG_LIFECYCLE = false;
+    
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(ActivityTests.class.getName());
+
+        suite.addTestSuite(BroadcastTest.class);
+        suite.addTestSuite(IntentSenderTest.class);
+        suite.addTestSuite(ActivityManagerTest.class);
+        suite.addTestSuite(LaunchTest.class);
+        suite.addTestSuite(LifecycleTest.class);
+        suite.addTestSuite(ServiceTest.class);
+        suite.addTestSuite(MetaDataTest.class);
+        // Remove temporarily until bug 1171309 is fixed.
+        //suite.addTestSuite(SubActivityTest.class);
+        suite.addTestSuite(SetTimeZonePermissionsTest.class);
+        
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java
new file mode 100644
index 0000000..f960969
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+
+public class ActivityTestsBase extends AndroidTestCase 
+        implements PerformanceTestCase, LaunchpadActivity.CallingTest {
+    public static final String PERMISSION_GRANTED =
+            "com.android.unit_tests.permission.TEST_GRANTED";
+    public static final String PERMISSION_DENIED =
+            "com.android.unit_tests.permission.TEST_DENIED";
+
+    protected Intent mIntent;
+
+    private PerformanceTestCase.Intermediates mIntermediates;
+    private String mExpecting;
+
+    // Synchronization of activity result.
+    private boolean mFinished;
+    private int mResultCode = 0;
+    private Intent mData;
+    private RuntimeException mResultStack = null;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mIntent = new Intent(mContext, LaunchpadActivity.class);
+        mIntermediates = null;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mIntermediates = null;
+        super.tearDown();
+    }
+
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+    public void setInternalIterations(int count) {
+    }
+
+    public void startTiming(boolean realTime) {
+        if (mIntermediates != null) {
+            mIntermediates.startTiming(realTime);
+        }
+    }
+
+    public void addIntermediate(String name) {
+        if (mIntermediates != null) {
+            mIntermediates.addIntermediate(name);
+        }
+    }
+
+    public void addIntermediate(String name, long timeInNS) {
+        if (mIntermediates != null) {
+            mIntermediates.addIntermediate(name, timeInNS);
+        }
+    }
+
+    public void finishTiming(boolean realTime) {
+        if (mIntermediates != null) {
+            mIntermediates.finishTiming(realTime);
+        }
+    }
+
+    public void activityFinished(int resultCode, Intent data, RuntimeException where) {
+        finishWithResult(resultCode, data, where);
+    }
+
+    public Intent editIntent() {
+        return mIntent;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public int startPerformance(Intermediates intermediates) {
+        mIntermediates = intermediates;
+        return 1;
+    }
+
+    public void finishGood() {
+        finishWithResult(Activity.RESULT_OK, null);
+    }
+
+    public void finishBad(String error) {
+        finishWithResult(Activity.RESULT_CANCELED, (new Intent()).setAction(error));
+    }
+
+    public void finishWithResult(int resultCode, Intent data) {
+        RuntimeException where = new RuntimeException("Original error was here");
+        where.fillInStackTrace();
+        finishWithResult(resultCode, data, where);
+    }
+
+    public void finishWithResult(int resultCode, Intent data, RuntimeException where) {
+        synchronized (this) {
+            //System.out.println("*** Activity finished!!");
+            mResultCode = resultCode;
+            mData = data;
+            mResultStack = where;
+            mFinished = true;
+            notifyAll();
+        }
+    }
+
+    public int runLaunchpad(String action) {
+        LaunchpadActivity.setCallingTest(this);
+
+        synchronized (this) {
+            mIntent.setAction(action);
+            mFinished = false;
+            //System.out.println("*** Starting: " + mIntent);
+            mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(mIntent);
+        }
+
+        return waitForResultOrThrow(60 * 1000);
+    }
+
+    public int waitForResultOrThrow(int timeoutMs) {
+        return waitForResultOrThrow(timeoutMs, null);
+    }
+
+    public int waitForResultOrThrow(int timeoutMs, String expected) {
+        int res = waitForResult(timeoutMs, expected);
+
+        if (res == Activity.RESULT_CANCELED) {
+            if (mResultStack != null) {
+                throw new RuntimeException(
+                        mData != null ? mData.toString() : "Unable to launch",
+                        mResultStack);
+            } else {
+                throw new RuntimeException(
+                        mData != null ? mData.toString() : "Unable to launch");
+            }
+        }
+        return res;
+    }
+
+    public int waitForResult(int timeoutMs, String expected) {
+        mExpecting = expected;
+
+        long endTime = System.currentTimeMillis() + timeoutMs;
+
+        boolean timeout = false;
+        synchronized (this) {
+            while (!mFinished) {
+                long delay = endTime - System.currentTimeMillis();
+                if (delay < 0) {
+                    timeout = true;
+                    break;
+                }
+
+                try {
+                    wait(delay);
+                } catch (java.lang.InterruptedException e) {
+                    // do nothing
+                }
+            }
+        }
+
+        mFinished = false;
+
+        if (timeout) {
+            mResultCode = Activity.RESULT_CANCELED;
+            onTimeout();
+        }
+        return mResultCode;
+    }
+
+    public int getResultCode() {
+        return mResultCode;
+    }
+    
+    public Intent getResultData() {
+        return mData;
+    }
+    
+    public RuntimeException getResultStack() {
+        return mResultStack;
+    }
+    
+    public void onTimeout() {
+        String msg = mExpecting == null
+                ? "Timeout" : ("Timeout while expecting " + mExpecting);
+        finishWithResult(Activity.RESULT_CANCELED, (new Intent()).setAction(msg));
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java
new file mode 100644
index 0000000..7f6db3c
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+import java.util.Arrays;
+
+public class BroadcastTest extends ActivityTestsBase {
+    public static final int BROADCAST_TIMEOUT = 5 * 1000;
+
+    public static final String BROADCAST_REGISTERED =
+            "com.android.unit_tests.activity.BROADCAST_REGISTERED";
+    public static final String BROADCAST_LOCAL =
+            "com.android.unit_tests.activity.BROADCAST_LOCAL";
+    public static final String BROADCAST_LOCAL_GRANTED =
+            "com.android.unit_tests.activity.BROADCAST_LOCAL_GRANTED";
+    public static final String BROADCAST_LOCAL_DENIED =
+            "com.android.unit_tests.activity.BROADCAST_LOCAL_DENIED";
+    public static final String BROADCAST_REMOTE =
+            "com.android.unit_tests.activity.BROADCAST_REMOTE";
+    public static final String BROADCAST_REMOTE_GRANTED =
+            "com.android.unit_tests.activity.BROADCAST_REMOTE_GRANTED";
+    public static final String BROADCAST_REMOTE_DENIED =
+            "com.android.unit_tests.activity.BROADCAST_REMOTE_DENIED";
+    public static final String BROADCAST_ALL =
+            "com.android.unit_tests.activity.BROADCAST_ALL";
+    public static final String BROADCAST_MULTI =
+            "com.android.unit_tests.activity.BROADCAST_MULTI";
+    public static final String BROADCAST_ABORT =
+            "com.android.unit_tests.activity.BROADCAST_ABORT";
+
+    public static final String BROADCAST_STICKY1 =
+            "com.android.unit_tests.activity.BROADCAST_STICKY1";
+    public static final String BROADCAST_STICKY2 =
+            "com.android.unit_tests.activity.BROADCAST_STICKY2";
+
+    public static final String BROADCAST_FAIL_REGISTER =
+            "com.android.unit_tests.activity.BROADCAST_FAIL_REGISTER";
+    public static final String BROADCAST_FAIL_BIND =
+            "com.android.unit_tests.activity.BROADCAST_FAIL_BIND";
+
+    public static final String RECEIVER_REG = "receiver-reg";
+    public static final String RECEIVER_LOCAL = "receiver-local";
+    public static final String RECEIVER_REMOTE = "receiver-remote";
+    public static final String RECEIVER_ABORT = "receiver-abort";
+    public static final String RECEIVER_RESULTS = "receiver-results";
+
+    public static final String DATA_1 = "one";
+    public static final String DATA_2 = "two";
+
+    public static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
+    public static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
+
+    private String[] mExpectedReceivers = null;
+    private int mNextReceiver;
+
+    private String[] mExpectedData = null;
+    private boolean[] mReceivedData = null;
+
+    boolean mReceiverRegistered = false;
+
+    public void setExpectedReceivers(String[] receivers) {
+        mExpectedReceivers = receivers;
+        mNextReceiver = 0;
+    }
+
+    public void setExpectedData(String[] data) {
+        mExpectedData = data;
+        mReceivedData = new boolean[data.length];
+    }
+
+    public void onTimeout() {
+        String msg = "Timeout";
+        if (mExpectedReceivers != null && mNextReceiver < mExpectedReceivers.length) {
+            msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
+        }
+        finishBad(msg);
+    }
+
+    public Intent makeBroadcastIntent(String action) {
+        Intent intent = new Intent(action, null);
+        intent.putExtra("caller", mCallTarget);
+        return intent;
+    }
+
+    public void finishWithResult(int resultCode, Intent data) {
+        unregisterMyReceiver();
+        super.finishWithResult(resultCode, data);
+    }
+
+    public final void gotReceive(String name, Intent intent) {
+        synchronized (this) {
+
+            //System.out.println("Got receive: " + name);
+            //System.out.println(mNextReceiver + " in " + mExpectedReceivers);
+            //new RuntimeException("stack").printStackTrace();
+
+            addIntermediate(name);
+
+            if (mExpectedData != null) {
+                int n = mExpectedData.length;
+                int i;
+                boolean prev = false;
+                for (i = 0; i < n; i++) {
+                    if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
+                        if (mReceivedData[i]) {
+                            prev = true;
+                            continue;
+                        }
+                        mReceivedData[i] = true;
+                        break;
+                    }
+                }
+                if (i >= n) {
+                    if (prev) {
+                        finishBad("Receive got data too many times: "
+                                + intent.getStringExtra("test"));
+                    } else {
+                        finishBad("Receive got unexpected data: "
+                                + intent.getStringExtra("test"));
+                    }
+                    new RuntimeException("stack").printStackTrace();
+                    return;
+                }
+            }
+
+            if (mNextReceiver >= mExpectedReceivers.length) {
+                finishBad("Got too many onReceiveIntent() calls!");
+//                System.out.println("Too many intents received: now at "
+//                        + mNextReceiver + ", expect list: "
+//                        + Arrays.toString(mExpectedReceivers));
+                fail("Got too many onReceiveIntent() calls!");
+            } else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
+                finishBad("Receive out of order: got " + name
+                        + " but expected "
+                        + mExpectedReceivers[mNextReceiver]);
+                fail("Receive out of order: got " + name
+                        + " but expected "
+                        + mExpectedReceivers[mNextReceiver]);
+            } else {
+                mNextReceiver++;
+                if (mNextReceiver == mExpectedReceivers.length) {
+                    finishTest();
+                }
+            }
+        }
+    }
+
+    public void registerMyReceiver(IntentFilter filter, String permission) {
+        mReceiverRegistered = true;
+        //System.out.println("Registering: " + mReceiver);
+        getContext().registerReceiver(mReceiver, filter, permission, null);
+    }
+
+    public void unregisterMyReceiver() {
+        if (mReceiverRegistered) {
+            unregisterMyReceiverNoCheck();
+        }
+    }
+
+    public void unregisterMyReceiverNoCheck() {
+        mReceiverRegistered = false;
+        //System.out.println("Unregistering: " + mReceiver);
+        getContext().unregisterReceiver(mReceiver);
+    }
+
+    public void onRegisteredReceiver(Intent intent) {
+        gotReceive(RECEIVER_REG, intent);
+    }
+
+    private Binder mCallTarget = new Binder() {
+        public boolean onTransact(int code, Parcel data, Parcel reply,
+                int flags) {
+            data.setDataPosition(0);
+            data.enforceInterface(LaunchpadActivity.LAUNCH);
+            if (code == GOT_RECEIVE_TRANSACTION) {
+                String name = data.readString();
+                gotReceive(name, null);
+                return true;
+            } else if (code == ERROR_TRANSACTION) {
+                finishBad(data.readString());
+                return true;
+            }
+            return false;
+        }
+    };
+
+    private void finishTest() {
+        if (mReceiverRegistered) {
+            addIntermediate("before-unregister");
+            unregisterMyReceiver();
+        }
+        finishTiming(true);
+        finishGood();
+    }
+
+    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            //System.out.println("Receive in: " + this + ": " + intent);
+            onRegisteredReceiver(intent);
+        }
+    };
+
+    // Mark flaky until http://b/issue?id=1191607 is resolved.
+    @FlakyTest(tolerance=2)
+    public void testRegistered() throws Exception {
+        runLaunchpad(LaunchpadActivity.BROADCAST_REGISTERED);
+    }
+
+    public void testLocal() throws Exception {
+        runLaunchpad(LaunchpadActivity.BROADCAST_LOCAL);
+    }
+
+    public void testRemote() throws Exception {
+        runLaunchpad(LaunchpadActivity.BROADCAST_REMOTE);
+    }
+
+    public void testAbort() throws Exception {
+        runLaunchpad(LaunchpadActivity.BROADCAST_ABORT);
+    }
+
+    @FlakyTest(tolerance=2)
+    public void testAll() throws Exception {
+        runLaunchpad(LaunchpadActivity.BROADCAST_ALL);
+    }
+
+    @FlakyTest(tolerance=2)
+    public void testMulti() throws Exception {
+        runLaunchpad(LaunchpadActivity.BROADCAST_MULTI);
+    }
+
+    private class TestBroadcastReceiver extends BroadcastReceiver {
+        public boolean mHaveResult = false;
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (BroadcastTest.this) {
+                mHaveResult = true;
+                BroadcastTest.this.notifyAll();
+            }
+        }
+    }
+
+    public void testResult() throws Exception {
+        TestBroadcastReceiver broadcastReceiver = new TestBroadcastReceiver();
+
+        synchronized (this) {
+            Bundle map = new Bundle();
+            map.putString("foo", "you");
+            map.putString("remove", "me");
+            getContext().sendOrderedBroadcast(
+                    new Intent("com.android.unit_tests.activity.BROADCAST_RESULT"),
+                    null, broadcastReceiver, null, 1, "foo", map);
+            while (!broadcastReceiver.mHaveResult) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+
+            //System.out.println("Code: " + mResultCode + ", data: " + mResultData);
+            //System.out.println("Extras: " + mResultExtras);
+
+            assertEquals("Incorrect code: " + broadcastReceiver.getResultCode(),
+                    3, broadcastReceiver.getResultCode());
+
+            assertEquals("bar", broadcastReceiver.getResultData());
+
+            Bundle resultExtras = broadcastReceiver.getResultExtras(false);
+            assertEquals("them", resultExtras.getString("bar"));
+            assertEquals("you", resultExtras.getString("foo"));
+            assertNull(resultExtras.getString("remove"));
+        }
+    }
+
+    public void testSetSticky() throws Exception {
+        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+        intent.putExtra("test", LaunchpadActivity.DATA_1);
+        ActivityManagerNative.getDefault().unbroadcastIntent(null, intent);
+
+        ActivityManagerNative.broadcastStickyIntent(intent, null);
+        addIntermediate("finished-broadcast");
+
+        IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
+        Intent sticky = getContext().registerReceiver(null, filter);
+        assertNotNull("Sticky not found", sticky);
+        assertEquals(LaunchpadActivity.DATA_1, sticky.getStringExtra("test"));
+    }
+
+    public void testClearSticky() throws Exception {
+        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+        intent.putExtra("test", LaunchpadActivity.DATA_1);
+        ActivityManagerNative.broadcastStickyIntent(intent, null);
+
+        ActivityManagerNative.getDefault().unbroadcastIntent(
+                null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null));
+        addIntermediate("finished-unbroadcast");
+
+        IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
+        Intent sticky = getContext().registerReceiver(null, filter);
+        assertNull("Sticky not found", sticky);
+    }
+
+    public void testReplaceSticky() throws Exception {
+        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+        intent.putExtra("test", LaunchpadActivity.DATA_1);
+        ActivityManagerNative.broadcastStickyIntent(intent, null);
+        intent.putExtra("test", LaunchpadActivity.DATA_2);
+
+        ActivityManagerNative.broadcastStickyIntent(intent, null);
+        addIntermediate("finished-broadcast");
+
+        IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
+        Intent sticky = getContext().registerReceiver(null, filter);
+        assertNotNull("Sticky not found", sticky);
+        assertEquals(LaunchpadActivity.DATA_2, sticky.getStringExtra("test"));
+    }
+
+    // Marking flaky until http://b/issue?id=1191337 is resolved
+    @FlakyTest(tolerance=2)
+    public void testReceiveSticky() throws Exception {
+        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+        intent.putExtra("test", LaunchpadActivity.DATA_1);
+        ActivityManagerNative.broadcastStickyIntent(intent, null);
+
+        runLaunchpad(LaunchpadActivity.BROADCAST_STICKY1);
+    }
+
+    // Marking flaky until http://b/issue?id=1191337 is resolved
+    @FlakyTest(tolerance=2)
+    public void testReceive2Sticky() throws Exception {
+        Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+        intent.putExtra("test", LaunchpadActivity.DATA_1);
+        ActivityManagerNative.broadcastStickyIntent(intent, null);
+        intent = new Intent(LaunchpadActivity.BROADCAST_STICKY2, null);
+        intent.putExtra("test", LaunchpadActivity.DATA_2);
+        ActivityManagerNative.broadcastStickyIntent(intent, null);
+
+        runLaunchpad(LaunchpadActivity.BROADCAST_STICKY2);
+    }
+
+    public void testRegisteredReceivePermissionGranted() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_REG});
+        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED);
+        addIntermediate("after-register");
+        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testRegisteredReceivePermissionDenied() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_DENIED);
+        addIntermediate("after-register");
+
+        BroadcastReceiver finish = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                gotReceive(RECEIVER_RESULTS, intent);
+            }
+        };
+
+        getContext().sendOrderedBroadcast(
+                makeBroadcastIntent(BROADCAST_REGISTERED),
+                null, finish, null, Activity.RESULT_CANCELED, null, null);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testRegisteredBroadcastPermissionGranted() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_REG});
+        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
+        addIntermediate("after-register");
+        getContext().sendBroadcast(
+                makeBroadcastIntent(BROADCAST_REGISTERED),
+                PERMISSION_GRANTED);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testRegisteredBroadcastPermissionDenied() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
+        addIntermediate("after-register");
+
+        BroadcastReceiver finish = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                gotReceive(RECEIVER_RESULTS, intent);
+            }
+        };
+
+        getContext().sendOrderedBroadcast(
+                makeBroadcastIntent(BROADCAST_REGISTERED),
+                PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
+                null, null);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testLocalReceivePermissionGranted() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL_GRANTED));
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testLocalReceivePermissionDenied() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+        BroadcastReceiver finish = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                gotReceive(RECEIVER_RESULTS, intent);
+            }
+        };
+
+        getContext().sendOrderedBroadcast(
+                makeBroadcastIntent(BROADCAST_LOCAL_DENIED),
+                null, finish, null, Activity.RESULT_CANCELED,
+                null, null);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testLocalBroadcastPermissionGranted() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+        getContext().sendBroadcast(
+                makeBroadcastIntent(BROADCAST_LOCAL),
+                PERMISSION_GRANTED);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testLocalBroadcastPermissionDenied() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+        BroadcastReceiver finish = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                gotReceive(RECEIVER_RESULTS, intent);
+            }
+        };
+
+        getContext().sendOrderedBroadcast(
+                makeBroadcastIntent(BROADCAST_LOCAL),
+                PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
+                null, null);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testRemoteReceivePermissionGranted() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_REMOTE});
+        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE_GRANTED));
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testRemoteReceivePermissionDenied() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+        BroadcastReceiver finish = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                gotReceive(RECEIVER_RESULTS, intent);
+            }
+        };
+
+        getContext().sendOrderedBroadcast(
+                makeBroadcastIntent(BROADCAST_REMOTE_DENIED),
+                null, finish, null, Activity.RESULT_CANCELED,
+                null, null);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testRemoteBroadcastPermissionGranted() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_REMOTE});
+        getContext().sendBroadcast(
+                makeBroadcastIntent(BROADCAST_REMOTE),
+                PERMISSION_GRANTED);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testRemoteBroadcastPermissionDenied() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+        BroadcastReceiver finish = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                gotReceive(RECEIVER_RESULTS, intent);
+            }
+        };
+
+        getContext().sendOrderedBroadcast(
+                makeBroadcastIntent(BROADCAST_REMOTE),
+                PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
+                null, null);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testReceiverCanNotRegister() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_REGISTER));
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testReceiverCanNotBind() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+        getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_BIND));
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+    }
+
+    public void testLocalUnregisterTwice() throws Exception {
+        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
+        unregisterMyReceiverNoCheck();
+        try {
+            unregisterMyReceiverNoCheck();
+            fail("No exception thrown on second unregister");
+        } catch (IllegalArgumentException e) {
+            Log.i("foo", "Unregister exception", e);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java
new file mode 100644
index 0000000..dd5274a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class ClearTop extends Activity {
+    public static final String WAIT_CLEAR_TASK = "waitClearTask";
+    
+    public ClearTop() {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        //Log.i("foo", "Creating: " + this);
+        Intent intent = new Intent(getIntent()).setAction(LocalScreen.CLEAR_TASK)
+                .setClass(this, LocalScreen.class);
+        startActivity(intent);
+    }
+    
+    @Override
+    public void onNewIntent(Intent intent) {
+        //Log.i("foo", "New intent in " + this + ": " + intent);
+        if (LocalScreen.CLEAR_TASK.equals(intent.getAction())) {
+            setResult(RESULT_OK);
+        } else {
+            setResult(RESULT_CANCELED, new Intent().setAction(
+                    "New intent received " + intent + ", expecting action "
+                    + TestedScreen.CLEAR_TASK));
+        }
+        finish();
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java
new file mode 100644
index 0000000..a30c1cb
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.suitebuilder.annotation.Suppress;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.Suppress;
+
+public class IntentSenderTest extends BroadcastTest {
+
+    public void testRegisteredReceivePermissionGranted() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_REG});
+        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED);
+        addIntermediate("after-register");
+        PendingIntent is = PendingIntent.getBroadcast(getContext(), 0,
+                makeBroadcastIntent(BROADCAST_REGISTERED), 0);
+        is.send();
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+        is.cancel();
+    }
+
+    public void testRegisteredReceivePermissionDenied() throws Exception {
+        final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED);
+
+        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+        registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_DENIED);
+        addIntermediate("after-register");
+
+        PendingIntent.OnFinished finish = new PendingIntent.OnFinished() {
+            public void onSendFinished(PendingIntent pi, Intent intent,
+                    int resultCode, String resultData, Bundle resultExtras) {
+                gotReceive(RECEIVER_RESULTS, intent);
+            }
+        };
+
+        PendingIntent is = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+        is.send(Activity.RESULT_CANCELED, finish, null);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+        is.cancel();
+    }
+
+    public void testLocalReceivePermissionGranted() throws Exception {
+        setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+        PendingIntent is = PendingIntent.getBroadcast(getContext(), 0,
+                makeBroadcastIntent(BROADCAST_LOCAL_GRANTED), 0);
+        is.send();
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+        is.cancel();
+    }
+
+    public void testLocalReceivePermissionDenied() throws Exception {
+        final Intent intent = makeBroadcastIntent(BROADCAST_LOCAL_DENIED);
+
+        setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+        PendingIntent.OnFinished finish = new PendingIntent.OnFinished() {
+            public void onSendFinished(PendingIntent pi, Intent intent,
+                    int resultCode, String resultData, Bundle resultExtras) {
+                gotReceive(RECEIVER_RESULTS, intent);
+            }
+        };
+
+        PendingIntent is = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+        is.send(Activity.RESULT_CANCELED, finish, null);
+        waitForResultOrThrow(BROADCAST_TIMEOUT);
+        is.cancel();
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java
new file mode 100644
index 0000000..12b1b5d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.ComponentName;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class LaunchTest extends ActivityTestsBase {
+
+    @LargeTest
+    public void testColdActivity() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), TestedActivity.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    @LargeTest
+    public void testLocalActivity() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), LocalActivity.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    @LargeTest
+    public void testColdScreen() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), TestedScreen.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    @LargeTest
+    public void testLocalScreen() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), LocalScreen.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    @LargeTest
+    public void testForwardResult() throws Exception {
+        runLaunchpad(LaunchpadActivity.FORWARD_RESULT);
+    }
+
+    // The following is disabled until we can catch and recover from
+    // application errors.
+    public void xxtestBadParcelable() throws Exception {
+        // All we really care about for this test is that the system
+        // doesn't crash.
+        runLaunchpad(LaunchpadActivity.BAD_PARCELABLE);
+    }
+
+    @LargeTest
+    public void testClearTopInCreate() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class));
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    @LargeTest
+    public void testClearTopWhileResumed() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class));
+        mIntent.putExtra(ClearTop.WAIT_CLEAR_TASK, true);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+}
+
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java
new file mode 100644
index 0000000..06e7a84
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.test.PerformanceTestCase;
+import android.util.Log;
+
+class MyBadParcelable implements Parcelable {
+    public MyBadParcelable() {
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString("I am bad");
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<MyBadParcelable> CREATOR
+            = new Parcelable.Creator<MyBadParcelable>() {
+        public MyBadParcelable createFromParcel(Parcel in) {
+            return new MyBadParcelable(in);
+        }
+
+        public MyBadParcelable[] newArray(int size) {
+            return new MyBadParcelable[size];
+        }
+    };
+
+    public MyBadParcelable(Parcel in) {
+        String nm = in.readString();
+    }
+}
+
+public class LaunchpadActivity extends Activity {
+    public interface CallingTest extends PerformanceTestCase.Intermediates {
+        public void startTiming(boolean realTime);
+        public void addIntermediate(String name);
+        public void addIntermediate(String name, long timeInNS);
+        public void finishTiming(boolean realTime);
+        public void activityFinished(int resultCode, Intent data,
+                RuntimeException where);
+    }
+
+    // Also used as the Binder interface descriptor string in these tests
+    public static final String LAUNCH = "com.android.unit_tests.activity.LAUNCH";
+
+    public static final String FORWARD_RESULT =
+            "com.android.unit_tests.activity.FORWARD_RESULT";
+    public static final String RETURNED_RESULT =
+            "com.android.unit_tests.activity.RETURNED_RESULT";
+
+    public static final String BAD_PARCELABLE =
+            "com.android.unit_tests.activity.BAD_PARCELABLE";
+
+    public static final int LAUNCHED_RESULT = 1;
+    public static final int FORWARDED_RESULT = 2;
+
+    public static final String LIFECYCLE_BASIC =
+            "com.android.unit_tests.activity.LIFECYCLE_BASIC";
+    public static final String LIFECYCLE_SCREEN =
+            "com.android.unit_tests.activity.LIFECYCLE_SCREEN";
+    public static final String LIFECYCLE_DIALOG =
+            "com.android.unit_tests.activity.LIFECYCLE_DIALOG";
+    public static final String LIFECYCLE_FINISH_CREATE =
+            "com.android.unit_tests.activity.LIFECYCLE_FINISH_CREATE";
+    public static final String LIFECYCLE_FINISH_START =
+            "com.android.unit_tests.activity.LIFECYCLE_FINISH_START";
+
+    public static final String BROADCAST_REGISTERED =
+            "com.android.unit_tests.activity.BROADCAST_REGISTERED";
+    public static final String BROADCAST_LOCAL =
+            "com.android.unit_tests.activity.BROADCAST_LOCAL";
+    public static final String BROADCAST_REMOTE =
+            "com.android.unit_tests.activity.BROADCAST_REMOTE";
+    public static final String BROADCAST_ALL =
+            "com.android.unit_tests.activity.BROADCAST_ALL";
+    public static final String BROADCAST_REPEAT =
+        "com.android.unit_tests.activity.BROADCAST_REPEAT";
+    public static final String BROADCAST_MULTI =
+            "com.android.unit_tests.activity.BROADCAST_MULTI";
+    public static final String BROADCAST_ABORT =
+            "com.android.unit_tests.activity.BROADCAST_ABORT";
+
+    public static final String BROADCAST_STICKY1 =
+            "com.android.unit_tests.activity.BROADCAST_STICKY1";
+    public static final String BROADCAST_STICKY2 =
+            "com.android.unit_tests.activity.BROADCAST_STICKY2";
+
+    public static final String RECEIVER_REG = "receiver-reg";
+    public static final String RECEIVER_LOCAL = "receiver-local";
+    public static final String RECEIVER_REMOTE = "receiver-remote";
+    public static final String RECEIVER_ABORT = "receiver-abort";
+
+    public static final String DATA_1 = "one";
+    public static final String DATA_2 = "two";
+
+    public static final String ON_START = "onStart";
+    public static final String ON_RESTART = "onRestart";
+    public static final String ON_RESUME = "onResume";
+    public static final String ON_FREEZE = "onSaveInstanceState";
+    public static final String ON_PAUSE = "onPause";
+    public static final String ON_STOP = "onStop";
+    public static final String ON_DESTROY = "onDestroy";
+
+    public static final String DO_FINISH = "finish";
+    public static final String DO_LOCAL_SCREEN = "local-screen";
+    public static final String DO_LOCAL_DIALOG = "local-dialog";
+
+    private boolean mBadParcelable = false;
+
+    private boolean mStarted = false;
+    private long mStartTime;
+
+    private int mResultCode = RESULT_CANCELED;
+    private Intent mData = (new Intent()).setAction("No result received");
+    private RuntimeException mResultStack = null;
+
+    private String[] mExpectedLifecycle = null;
+    private int mNextLifecycle;
+
+    private String[] mExpectedReceivers = null;
+    private int mNextReceiver;
+
+    private String[] mExpectedData = null;
+    private boolean[] mReceivedData = null;
+
+    boolean mReceiverRegistered = false;
+
+    private static CallingTest sCallingTest = null;
+
+    public static void setCallingTest(CallingTest ct) {
+        sCallingTest = ct;
+    }
+
+    public LaunchpadActivity() {
+        mStartTime = System.currentTimeMillis();
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        String action = getIntent().getAction();
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "CREATE lauchpad "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+        if (LIFECYCLE_BASIC.equals(action)) {
+            setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
+                    DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
+        } else if (LIFECYCLE_SCREEN.equals(action)) {
+            setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
+                    DO_LOCAL_SCREEN, ON_FREEZE, ON_PAUSE, ON_STOP,
+                    ON_RESTART, ON_START, ON_RESUME,
+                    DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
+        } else if (LIFECYCLE_DIALOG.equals(action)) {
+            setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
+                    DO_LOCAL_DIALOG, ON_FREEZE, ON_PAUSE, ON_RESUME,
+                    DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
+        } else if (LIFECYCLE_FINISH_CREATE.equals(action)) {
+            // This one behaves a little differently when running in a group.
+            if (getParent() == null) {
+                setExpectedLifecycle(new String[]{ON_DESTROY});
+            } else {
+                setExpectedLifecycle(new String[]{ON_START, ON_STOP, ON_DESTROY});
+            }
+            finish();
+        } else if (LIFECYCLE_FINISH_START.equals(action)) {
+            setExpectedLifecycle(new String[]{ON_START, DO_FINISH,
+                    ON_STOP, ON_DESTROY});
+        }
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "START lauchpad "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+        checkLifecycle(ON_START);
+    }
+
+    @Override
+    protected void onRestart() {
+        super.onStart();
+        checkLifecycle(ON_RESTART);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "RESUME lauchpad "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+        checkLifecycle(ON_RESUME);
+
+        if (!mStarted) {
+            mStarted = true;
+
+            mHandler.postDelayed(mTimeout, 5 * 1000);
+
+            String action = getIntent().getAction();
+
+            sCallingTest.startTiming(true);
+
+            if (LAUNCH.equals(action)) {
+                Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setComponent((ComponentName)
+                        intent.getParcelableExtra("component"));
+                //System.out.println("*** Launchpad is starting: comp=" + intent.component);
+                startActivityForResult(intent, LAUNCHED_RESULT);
+            } else if (FORWARD_RESULT.equals(action)) {
+                Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setClass(this, LocalScreen.class);
+                startActivityForResult(intent, FORWARDED_RESULT);
+            } else if (BAD_PARCELABLE.equals(action)) {
+                mBadParcelable = true;
+                Intent intent = getIntent();
+                intent.setFlags(0);
+                intent.setClass(this, LocalScreen.class);
+                startActivityForResult(intent, LAUNCHED_RESULT);
+            } else if (BROADCAST_REGISTERED.equals(action)) {
+                setExpectedReceivers(new String[]{RECEIVER_REG});
+                registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED));
+                sCallingTest.addIntermediate("after-register");
+                sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
+            } else if (BROADCAST_LOCAL.equals(action)) {
+                setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+                sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL));
+            } else if (BROADCAST_REMOTE.equals(action)) {
+                setExpectedReceivers(new String[]{RECEIVER_REMOTE});
+                sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE));
+            } else if (BROADCAST_ALL.equals(action)) {
+                setExpectedReceivers(new String[]{
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL});
+                registerMyReceiver(new IntentFilter(BROADCAST_ALL));
+                sCallingTest.addIntermediate("after-register");
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+            } else if (BROADCAST_MULTI.equals(action)) {
+                setExpectedReceivers(new String[]{
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+                        RECEIVER_LOCAL, RECEIVER_REMOTE,
+                        RECEIVER_LOCAL, RECEIVER_REMOTE,
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_LOCAL,
+                        RECEIVER_REMOTE, RECEIVER_LOCAL});
+                registerMyReceiver(new IntentFilter(BROADCAST_ALL));
+                sCallingTest.addIntermediate("after-register");
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REPEAT), null);
+            } else if (BROADCAST_ABORT.equals(action)) {
+                setExpectedReceivers(new String[]{
+                        RECEIVER_REMOTE, RECEIVER_ABORT});
+                registerMyReceiver(new IntentFilter(BROADCAST_ABORT));
+                sCallingTest.addIntermediate("after-register");
+                sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ABORT), null);
+            } else if (BROADCAST_STICKY1.equals(action)) {
+                setExpectedReceivers(new String[]{RECEIVER_REG});
+                setExpectedData(new String[]{DATA_1});
+                registerMyReceiver(new IntentFilter(BROADCAST_STICKY1));
+                sCallingTest.addIntermediate("after-register");
+            } else if (BROADCAST_STICKY2.equals(action)) {
+                setExpectedReceivers(new String[]{RECEIVER_REG, RECEIVER_REG});
+                setExpectedData(new String[]{DATA_1, DATA_2});
+                IntentFilter filter = new IntentFilter(BROADCAST_STICKY1);
+                filter.addAction(BROADCAST_STICKY2);
+                registerMyReceiver(filter);
+                sCallingTest.addIntermediate("after-register");
+            }
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        checkLifecycle(ON_FREEZE);
+        if (mBadParcelable) {
+            icicle.putParcelable("baddy", new MyBadParcelable());
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "PAUSE lauchpad "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+        checkLifecycle(ON_PAUSE);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "STOP lauchpad "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+        checkLifecycle(ON_STOP);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode,
+            Intent data) {
+        switch (requestCode) {
+            case LAUNCHED_RESULT:
+                sCallingTest.finishTiming(true);
+                finishWithResult(resultCode, data);
+                break;
+            case FORWARDED_RESULT:
+                sCallingTest.finishTiming(true);
+                if (RETURNED_RESULT.equals(data.getAction())) {
+                    finishWithResult(resultCode, data);
+                } else {
+                    finishWithResult(RESULT_CANCELED, (new Intent()).setAction(
+                            "Bad data returned: " + data));
+                }
+                break;
+            default:
+                sCallingTest.finishTiming(true);
+                finishWithResult(RESULT_CANCELED, (new Intent()).setAction(
+                        "Unexpected request code: " + requestCode));
+                break;
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "DESTROY lauchpad "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+        checkLifecycle(ON_DESTROY);
+        sCallingTest.activityFinished(mResultCode, mData, mResultStack);
+    }
+
+    private void setExpectedLifecycle(String[] lifecycle) {
+        mExpectedLifecycle = lifecycle;
+        mNextLifecycle = 0;
+    }
+
+    private void checkLifecycle(String where) {
+        if (mExpectedLifecycle == null) return;
+
+        if (mNextLifecycle >= mExpectedLifecycle.length) {
+            finishBad("Activity lifecycle incorrect: received " + where
+                    + " but don't expect any more calls");
+            mExpectedLifecycle = null;
+            return;
+        }
+        if (!mExpectedLifecycle[mNextLifecycle].equals(where)) {
+            finishBad("Activity lifecycle incorrect: received " + where
+                    + " but expected " + mExpectedLifecycle[mNextLifecycle]
+                    + " at " + mNextLifecycle);
+            mExpectedLifecycle = null;
+            return;
+        }
+
+        mNextLifecycle++;
+
+        if (mNextLifecycle >= mExpectedLifecycle.length) {
+            setTestResult(RESULT_OK, null);
+            return;
+        }
+
+        String next = mExpectedLifecycle[mNextLifecycle];
+        if (where.equals(ON_DESTROY)) {
+            finishBad("Activity lifecycle incorrect: received " + where
+                    + " but expected more actions (next is " + next + ")");
+            mExpectedLifecycle = null;
+            return;
+        } else if (next.equals(DO_FINISH)) {
+            mNextLifecycle++;
+            if (mNextLifecycle >= mExpectedLifecycle.length) {
+                setTestResult(RESULT_OK, null);
+            }
+            if (!isFinishing()) {
+                finish();
+            }
+        } else if (next.equals(DO_LOCAL_SCREEN)) {
+            mNextLifecycle++;
+            Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
+            intent.setClass(this, LocalScreen.class);
+            startActivity(intent);
+        } else if (next.equals(DO_LOCAL_DIALOG)) {
+            mNextLifecycle++;
+            Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
+            intent.setClass(this, LocalDialog.class);
+            startActivity(intent);
+        }
+    }
+
+    private void setExpectedReceivers(String[] receivers) {
+        mExpectedReceivers = receivers;
+        mNextReceiver = 0;
+    }
+
+    private void setExpectedData(String[] data) {
+        mExpectedData = data;
+        mReceivedData = new boolean[data.length];
+    }
+
+    private Intent makeBroadcastIntent(String action) {
+        Intent intent = new Intent(action, null);
+        intent.putExtra("caller", mCallTarget);
+        return intent;
+    }
+
+    private void finishGood() {
+        finishWithResult(RESULT_OK, null);
+    }
+
+    private void finishBad(String error) {
+        finishWithResult(RESULT_CANCELED, (new Intent()).setAction(error));
+    }
+
+    private void finishWithResult(int resultCode, Intent data) {
+        setTestResult(resultCode, data);
+        finish();
+    }
+
+    private void setTestResult(int resultCode, Intent data) {
+        mHandler.removeCallbacks(mTimeout);
+        unregisterMyReceiver();
+        mResultCode = resultCode;
+        mData = data;
+        mResultStack = new RuntimeException("Original error was here");
+        mResultStack.fillInStackTrace();
+    }
+
+    private void registerMyReceiver(IntentFilter filter) {
+        mReceiverRegistered = true;
+        //System.out.println("Registering: " + mReceiver);
+        registerReceiver(mReceiver, filter);
+    }
+
+    private void unregisterMyReceiver() {
+        if (mReceiverRegistered) {
+            mReceiverRegistered = false;
+            //System.out.println("Unregistering: " + mReceiver);
+            unregisterReceiver(mReceiver);
+        }
+    }
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+        }
+    };
+
+    static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
+    static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
+
+    private Binder mCallTarget = new Binder() {
+        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
+            data.setDataPosition(0);
+            data.enforceInterface(LaunchpadActivity.LAUNCH);
+            if (code == GOT_RECEIVE_TRANSACTION) {
+                String name = data.readString();
+                gotReceive(name, null);
+                return true;
+            } else if (code == ERROR_TRANSACTION) {
+                finishBad(data.readString());
+                return true;
+            }
+            return false;
+        }
+    };
+
+    private final void gotReceive(String name, Intent intent) {
+        synchronized (this) {
+
+            //System.out.println("Got receive: " + name);
+            //System.out.println(mNextReceiver + " in " + mExpectedReceivers);
+            //new RuntimeException("stack").printStackTrace();
+
+            sCallingTest.addIntermediate(mNextReceiver + "-" + name);
+
+            if (mExpectedData != null) {
+                int n = mExpectedData.length;
+                int i;
+                boolean prev = false;
+                for (i = 0; i < n; i++) {
+                    if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
+                        if (mReceivedData[i]) {
+                            prev = true;
+                            continue;
+                        }
+                        mReceivedData[i] = true;
+                        break;
+                    }
+                }
+                if (i >= n) {
+                    if (prev) {
+                        finishBad("Receive got data too many times: "
+                                + intent.getStringExtra("test"));
+                    } else {
+                        finishBad("Receive got unexpected data: "
+                                + intent.getStringExtra("test"));
+                    }
+                    return;
+                }
+            }
+
+            if (mNextReceiver >= mExpectedReceivers.length) {
+                finishBad("Got too many onReceiveIntent() calls!");
+//                System.out.println("Too many intents received: now at "
+//                                   + mNextReceiver + ", expect list: "
+//                                   + Arrays.toString(mExpectedReceivers));
+            } else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
+                finishBad("Receive out of order: got " + name + " but expected "
+                        + mExpectedReceivers[mNextReceiver] + " at "
+                        + mNextReceiver);
+            } else {
+                mNextReceiver++;
+                if (mNextReceiver == mExpectedReceivers.length) {
+                    mHandler.post(mUnregister);
+                }
+            }
+
+        }
+    }
+
+    private Runnable mUnregister = new Runnable() {
+        public void run() {
+            if (mReceiverRegistered) {
+                sCallingTest.addIntermediate("before-unregister");
+                unregisterMyReceiver();
+            }
+            sCallingTest.finishTiming(true);
+            finishGood();
+        }
+    };
+
+    private Runnable mTimeout = new Runnable() {
+        public void run() {
+            Log.i("foo", "**** TIMEOUT");
+            String msg = "Timeout";
+            if (mExpectedReceivers != null
+                    && mNextReceiver < mExpectedReceivers.length) {
+                msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
+            }
+            finishBad(msg);
+        }
+    };
+
+    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            //System.out.println("Receive in: " + this + ": " + intent);
+            gotReceive(RECEIVER_REG, intent);
+        }
+    };
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java
new file mode 100644
index 0000000..1e0e4a6
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.TabActivity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.TabHost;
+
+public class LaunchpadTabActivity extends TabActivity {
+    public LaunchpadTabActivity() {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        Intent tabIntent = new Intent(getIntent());
+        tabIntent.setComponent((ComponentName)tabIntent.getParcelableExtra("tab"));
+        
+        TabHost th = getTabHost();
+        TabHost.TabSpec ts = th.newTabSpec("1");
+        ts.setIndicator("One");
+        ts.setContent(tabIntent);
+        th.addTab(ts);
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java
new file mode 100644
index 0000000..fdc12ce
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+public class LifecycleTest extends ActivityTestsBase {
+    private Intent mTopIntent;
+    private Intent mTabIntent;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTopIntent = mIntent;
+        mTabIntent = new Intent(mContext, LaunchpadTabActivity.class);
+        mTabIntent.putExtra("tab", new ComponentName(mContext,
+                LaunchpadActivity.class));
+    }
+
+    @LargeTest
+    public void testBasic() throws Exception {
+        mIntent = mTopIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
+    }
+
+    //Suppressing until 1285425 is fixed.
+    @Suppress
+    public void testTabBasic() throws Exception {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
+    }
+
+    //Marking flaky until bug 1164344 is fixed.
+    @FlakyTest(tolerance=2)
+    @LargeTest
+    public void testScreen() throws Exception {
+        mIntent = mTopIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
+    }
+
+    //Marking flaky until bug 1164344 is fixed.
+    //@FlakyTest(tolerance=2)
+    //Suppressing until 1285425 is fixed.
+    @Suppress
+    public void testTabScreen() throws Exception {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
+    }
+
+    @LargeTest
+    public void testDialog() throws Exception {
+        mIntent = mTopIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
+    }
+
+    //Suppressing until 1285425 is fixed.
+    @Suppress
+    public void testTabDialog() throws Exception {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
+    }
+
+    @MediumTest
+    public void testFinishCreate() throws Exception {
+        mIntent = mTopIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_CREATE);
+    }
+
+    //Suppressing until 1285425 is fixed.
+    @Suppress
+    public void testTabFinishCreate() throws Exception {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_CREATE);
+    }
+
+    @MediumTest
+    public void testFinishStart() throws Exception {
+        mIntent = mTopIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_START);
+    }
+    
+    //Suppressing until 1285425 is fixed.
+    @Suppress
+    public void testTabFinishStart() throws Exception {
+        mIntent = mTabIntent;
+        runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_START);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java
new file mode 100644
index 0000000..3c107be
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+
+public class LocalActivity extends TestedActivity
+{
+    public LocalActivity()
+    {
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java
new file mode 100644
index 0000000..ac235c0
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+class LocalDeniedReceiver extends BroadcastReceiver {
+    public LocalDeniedReceiver() {
+    }
+
+    public void onReceive(Context context, Intent intent) {
+        try {
+            IBinder caller = intent.getIBinderExtra("caller");
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+            data.writeString(BroadcastTest.RECEIVER_LOCAL);
+            caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0);
+            data.recycle();
+        } catch (RemoteException ex) {
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java
new file mode 100644
index 0000000..0473ea9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+public class LocalDeniedService extends LocalService
+{
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java
new file mode 100644
index 0000000..3694375
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+
+public class LocalDialog extends TestedScreen
+{
+    public LocalDialog()
+    {
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java
new file mode 100644
index 0000000..48f5658
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class LocalGrantedReceiver extends BroadcastReceiver {
+    public LocalGrantedReceiver() {
+    }
+
+    public void onReceive(Context context, Intent intent) {
+        try {
+            IBinder caller = intent.getIBinderExtra("caller");
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+            data.writeString(BroadcastTest.RECEIVER_LOCAL);
+            caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0);
+            data.recycle();
+        } catch (RemoteException ex) {
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java
new file mode 100644
index 0000000..0dbcd00
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+public class LocalGrantedService extends LocalService
+{
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java
new file mode 100644
index 0000000..a3375bd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.activity;
+
+import android.content.UriMatcher;
+import android.content.*;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.util.Config;
+import android.util.Log;
+
+/** Simple test provider that runs in the local process. */
+public class LocalProvider extends ContentProvider {
+    private static final String TAG = "LocalProvider";
+
+    private SQLiteOpenHelper mOpenHelper;
+
+    private static final int DATA = 1;
+    private static final int DATA_ID = 2;
+    private static final UriMatcher sURLMatcher = new UriMatcher(
+            UriMatcher.NO_MATCH);
+
+    static {
+        sURLMatcher.addURI("*", "data", DATA);
+        sURLMatcher.addURI("*", "data/#", DATA_ID);
+    }
+
+    private static class DatabaseHelper extends SQLiteOpenHelper {
+        private static final String DATABASE_NAME = "local.db";
+        private static final int DATABASE_VERSION = 1;
+
+        public DatabaseHelper(Context context) {
+            super(context, DATABASE_NAME, null, DATABASE_VERSION);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE data (" +
+                       "_id INTEGER PRIMARY KEY," +
+                       "text TEXT, " +
+                       "integer INTEGER);");
+
+            // insert alarms
+            db.execSQL("INSERT INTO data (text, integer) VALUES ('first data', 100);");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
+            Log.w(TAG, "Upgrading test database from version " +
+                  oldVersion + " to " + currentVersion +
+                  ", which will destroy all old data");
+            db.execSQL("DROP TABLE IF EXISTS data");
+            onCreate(db);
+        }
+    }
+
+
+    public LocalProvider() {
+    }
+
+    @Override
+    public boolean onCreate() {
+        mOpenHelper = new DatabaseHelper(getContext());
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri url, String[] projectionIn, String selection,
+            String[] selectionArgs, String sort) {
+        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+
+        // Generate the body of the query
+        int match = sURLMatcher.match(url);
+        switch (match) {
+            case DATA:
+                qb.setTables("data");
+                break;
+            case DATA_ID:
+                qb.setTables("data");
+                qb.appendWhere("_id=");
+                qb.appendWhere(url.getPathSegments().get(1));
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown URL " + url);
+        }
+
+        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+        Cursor ret = qb.query(db, projectionIn, selection, selectionArgs,
+                              null, null, sort);
+
+        if (ret == null) {
+            if (Config.LOGD) Log.d(TAG, "Alarms.query: failed");
+        } else {
+            ret.setNotificationUri(getContext().getContentResolver(), url);
+        }
+
+        return ret;
+    }
+
+    @Override
+    public String getType(Uri url) {
+        int match = sURLMatcher.match(url);
+        switch (match) {
+            case DATA:
+                return "vnd.android.cursor.dir/vnd.google.unit_tests.local";
+            case DATA_ID:
+                return "vnd.android.cursor.item/vnd.google.unit_tests.local";
+            default:
+                throw new IllegalArgumentException("Unknown URL");
+        }
+    }
+
+    @Override
+    public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
+        int count;
+        long rowId = 0;
+        int match = sURLMatcher.match(url);
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        switch (match) {
+            case DATA_ID: {
+                String segment = url.getPathSegments().get(1);
+                rowId = Long.parseLong(segment);
+                count = db.update("data", values, "_id=" + rowId, null);
+                break;
+            }
+            default: {
+                throw new UnsupportedOperationException(
+                        "Cannot update URL: " + url);
+            }
+        }
+        if (Config.LOGD) Log.d(TAG, "*** notifyChange() rowId: " + rowId);
+        getContext().getContentResolver().notifyChange(url, null);
+        return count;
+    }
+
+
+    @Override
+    public Uri insert(Uri url, ContentValues initialValues) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri url, String where, String[] whereArgs) {
+        throw new UnsupportedOperationException("delete not supported");
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java
new file mode 100644
index 0000000..019c5c0
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ReceiverCallNotAllowedException;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class LocalReceiver extends BroadcastReceiver {
+    public LocalReceiver() {
+    }
+
+    public void onReceive(Context context, Intent intent) {
+        String resultString = LaunchpadActivity.RECEIVER_LOCAL;
+        if (BroadcastTest.BROADCAST_FAIL_REGISTER.equals(intent.getAction())) {
+            resultString = "Successfully registered, but expected it to fail";
+            try {
+                context.registerReceiver(this, new IntentFilter("foo.bar"));
+                context.unregisterReceiver(this);
+            } catch (ReceiverCallNotAllowedException e) {
+                //resultString = "This is the correct behavior but not yet implemented";
+                resultString = LaunchpadActivity.RECEIVER_LOCAL;
+            }
+        } else if (BroadcastTest.BROADCAST_FAIL_BIND.equals(intent.getAction())) {
+            resultString = "Successfully bound to service, but expected it to fail";
+            try {
+                ServiceConnection sc = new ServiceConnection() {
+                    public void onServiceConnected(ComponentName name, IBinder service) {
+                    }
+
+                    public void onServiceDisconnected(ComponentName name) {
+                    }
+                };
+                context.bindService(new Intent(context, LocalService.class), sc, 0);
+                context.unbindService(sc);
+            } catch (ReceiverCallNotAllowedException e) {
+                //resultString = "This is the correct behavior but not yet implemented";
+                resultString = LaunchpadActivity.RECEIVER_LOCAL;
+            }
+        } else if (LaunchpadActivity.BROADCAST_REPEAT.equals(intent.getAction())) {
+            Intent newIntent = new Intent(intent);
+            newIntent.setAction(LaunchpadActivity.BROADCAST_LOCAL);
+            context.sendOrderedBroadcast(newIntent, null);
+        }
+        try {
+            IBinder caller = intent.getIBinderExtra("caller");
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+            data.writeString(resultString);
+            caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0);
+            data.recycle();
+        } catch (RemoteException ex) {
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java
new file mode 100644
index 0000000..ad65fcc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+
+public class LocalScreen extends TestedScreen
+{
+    public LocalScreen()
+    {
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java
new file mode 100644
index 0000000..d79205d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.util.Log;
+
+public class LocalService extends Service {
+    private final IBinder mBinder = new Binder() {
+
+        @Override
+        protected boolean onTransact(int code, Parcel data, Parcel reply,
+                int flags) throws RemoteException {
+            if (code == ServiceTest.SET_REPORTER_CODE) {
+                data.enforceInterface(ServiceTest.SERVICE_LOCAL);
+                mReportObject = data.readStrongBinder();
+                return true;
+            } else {
+                return super.onTransact(code, data, reply, flags);
+            }
+        }
+        
+    };
+
+    private IBinder mReportObject;
+    private int mStartCount = 1;
+
+    public LocalService() {
+    }
+
+    @Override
+    public void onStart(Intent intent, int startId) {
+        //Log.i("LocalService", "onStart: " + intent);
+        if (intent.getExtras() != null) {
+            mReportObject = intent.getExtras().getIBinder(ServiceTest.REPORT_OBJ_NAME);
+            if (mReportObject != null) {
+                try {
+                    Parcel data = Parcel.obtain();
+                    data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
+                    data.writeInt(mStartCount);
+                    mStartCount++;
+                    mReportObject.transact(
+                            ServiceTest.STARTED_CODE, data, null, 0);
+                    data.recycle();
+                } catch (RemoteException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        Log.i("LocalService", "onDestroy: mReportObject=" + mReportObject);
+        if (mReportObject != null) {
+            try {
+                Parcel data = Parcel.obtain();
+                data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
+                mReportObject.transact(
+                        ServiceTest.DESTROYED_CODE, data, null, 0);
+                data.recycle();
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        Log.i("LocalService", "onBind: " + intent);
+        return mBinder;
+    }
+    
+    @Override
+    public boolean onUnbind(Intent intent) {
+        Log.i("LocalService", "onUnbind: " + intent);
+        if (mReportObject != null) {
+            try {
+                Parcel data = Parcel.obtain();
+                data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
+                mReportObject.transact(
+                        ServiceTest.UNBIND_CODE, data, null, 0);
+                data.recycle();
+            } catch (RemoteException e) {
+            }
+        }
+        return true;
+    }
+    
+    @Override
+    public void onRebind(Intent intent) {
+        Log.i("LocalService", "onUnbind: " + intent);
+        if (mReportObject != null) {
+            try {
+                Parcel data = Parcel.obtain();
+                data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
+                mReportObject.transact(
+                        ServiceTest.REBIND_CODE, data, null, 0);
+                data.recycle();
+            } catch (RemoteException e) {
+            }
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java
new file mode 100644
index 0000000..4660e29
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.unit_tests.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Tests for meta-data associated with application components.
+ */
+public class MetaDataTest extends AndroidTestCase {
+
+    private void checkMetaData(ComponentName cn, PackageItemInfo ci)
+            throws IOException, XmlPullParserException {
+        assertNotNull("Unable to find component " + cn, ci);
+
+        Bundle md = ci.metaData;
+        assertNotNull("No meta data found", md);
+
+        assertEquals("foo", md.getString("com.android.unit_tests.string"));
+        assertTrue(md.getBoolean("com.android.unit_tests.boolean"));
+        assertEquals(100, md.getInt("com.android.unit_tests.integer"));
+        assertEquals(0xff000000, md.getInt("com.android.unit_tests.color"));
+
+        assertEquals((double) 1001,
+                Math.floor(md.getFloat("com.android.unit_tests.float") * 10 + .5));
+
+        assertEquals(R.xml.metadata, md.getInt("com.android.unit_tests.reference"));
+
+        XmlResourceParser xml = ci.loadXmlMetaData(mContext.getPackageManager(),
+                "com.android.unit_tests.reference");
+        assertNotNull(xml);
+
+        int type;
+        while ((type = xml.next()) != XmlPullParser.START_TAG
+                && type != XmlPullParser.END_DOCUMENT) {
+        }
+        assertEquals(XmlPullParser.START_TAG, type);
+        assertEquals("thedata", xml.getName());
+
+        // method 1: direct access
+        final String rawAttr = xml.getAttributeValue(null, "rawText");
+        assertEquals("some raw text", rawAttr);
+
+        // method 2: direct access of typed value
+        final int rawColorIntAttr = xml.getAttributeIntValue(null, "rawColor", 0);
+        assertEquals(0xffffff00, rawColorIntAttr);
+        final String rawColorStrAttr = xml.getAttributeValue(null, "rawColor");
+        assertEquals("#ffffff00", rawColorStrAttr);
+
+        // method 2: direct access of resource attribute
+        final String nameSpace = "http://schemas.android.com/apk/res/android";
+        final int colorIntAttr = xml.getAttributeIntValue(nameSpace, "color", 0);
+        assertEquals(0xffff0000, colorIntAttr);
+        final String colorStrAttr = xml.getAttributeValue(nameSpace, "color");
+        assertEquals("#ffff0000", colorStrAttr);
+
+        // method 3: styled access (borrowing an attr from view system here)
+        TypedArray a = mContext.obtainStyledAttributes(xml,
+                android.R.styleable.TextView);
+        String styledAttr = a.getString(android.R.styleable.TextView_text);
+        assertEquals("text", styledAttr);
+        a.recycle();
+        
+        xml.close();
+    }
+
+    @SmallTest
+    public void testActivityWithData() throws Exception {
+        ComponentName cn = new ComponentName(mContext, LocalActivity.class);
+        ActivityInfo ai = mContext.getPackageManager().getActivityInfo(
+                cn, PackageManager.GET_META_DATA);
+
+        checkMetaData(cn, ai);
+
+        ai = mContext.getPackageManager().getActivityInfo(cn, 0);
+
+        assertNull("Meta data returned when not requested", ai.metaData);
+    }
+
+    @SmallTest
+    public void testReceiverWithData() throws Exception {
+        ComponentName cn = new ComponentName(mContext, LocalReceiver.class);
+        ActivityInfo ai = mContext.getPackageManager().getReceiverInfo(
+                cn, PackageManager.GET_META_DATA);
+
+        checkMetaData(cn, ai);
+
+        ai = mContext.getPackageManager().getReceiverInfo(cn, 0);
+
+        assertNull("Meta data returned when not requested", ai.metaData);
+    }
+
+    @SmallTest
+    public void testServiceWithData() throws Exception {
+        ComponentName cn = new ComponentName(mContext, LocalService.class);
+        ServiceInfo si = mContext.getPackageManager().getServiceInfo(
+                cn, PackageManager.GET_META_DATA);
+
+        checkMetaData(cn, si);
+
+        si = mContext.getPackageManager().getServiceInfo(cn, 0);
+
+        assertNull("Meta data returned when not requested", si.metaData);
+    }
+
+    @MediumTest
+    public void testProviderWithData() throws Exception {
+        ComponentName cn = new ComponentName(mContext, LocalProvider.class);
+        ProviderInfo pi = mContext.getPackageManager().resolveContentProvider(
+                "com.android.unit_tests.LocalProvider",
+                PackageManager.GET_META_DATA);
+        checkMetaData(cn, pi);
+
+        pi = mContext.getPackageManager().resolveContentProvider(
+                "com.android.unit_tests.LocalProvider", 0);
+
+        assertNull("Meta data returned when not requested", pi.metaData);
+    }
+
+    @SmallTest
+    public void testPermissionWithData() throws Exception {
+        ComponentName cn = new ComponentName("foo",
+                "com.android.unit_tests.permission.TEST_GRANTED");
+        PermissionInfo pi = mContext.getPackageManager().getPermissionInfo(
+                cn.getClassName(), PackageManager.GET_META_DATA);
+        checkMetaData(cn, pi);
+
+        pi = mContext.getPackageManager().getPermissionInfo(
+                cn.getClassName(), 0);
+
+        assertNull("Meta data returned when not requested", pi.metaData);
+    }
+}
+
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java
new file mode 100644
index 0000000..7656580
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+class RemoteDeniedReceiver extends BroadcastReceiver {
+    public RemoteDeniedReceiver() {
+    }
+
+    public void onReceive(Context context, Intent intent) {
+        try {
+            IBinder caller = intent.getIBinderExtra("caller");
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+            data.writeString(BroadcastTest.RECEIVER_REMOTE);
+            caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0);
+            data.recycle();
+        } catch (RemoteException ex) {
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java
new file mode 100644
index 0000000..034aa1d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class RemoteGrantedReceiver extends BroadcastReceiver {
+    public RemoteGrantedReceiver() {
+    }
+
+    public void onReceive(Context context, Intent intent) {
+        try {
+            IBinder caller = intent.getIBinderExtra("caller");
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+            data.writeString(BroadcastTest.RECEIVER_REMOTE);
+            caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0);
+            data.recycle();
+        } catch (RemoteException ex) {
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java
new file mode 100644
index 0000000..818bffe
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class RemoteReceiver extends BroadcastReceiver
+{
+    public RemoteReceiver()
+    {
+    }
+
+    public void onReceive(Context context, Intent intent)
+    {
+        if (LaunchpadActivity.BROADCAST_REPEAT.equals(intent.getAction())) {
+            Intent newIntent = new Intent(intent);
+            newIntent.setAction(LaunchpadActivity.BROADCAST_REMOTE);
+            context.sendOrderedBroadcast(newIntent, null);
+        }
+        try {
+            IBinder caller = intent.getIBinderExtra("caller");
+            Parcel data = Parcel.obtain();
+            data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+            data.writeString(LaunchpadActivity.RECEIVER_REMOTE);
+            caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0);
+            data.recycle();
+        } catch (RemoteException ex) {
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java
new file mode 100644
index 0000000..e750ed6
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java
@@ -0,0 +1,59 @@
+/* //device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+package com.android.unit_tests.activity;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.util.Log;
+
+public class RemoteSubActivityScreen extends SubActivityScreen {
+	Handler mHandler = new Handler();
+	boolean mFirst = false;
+
+    public RemoteSubActivityScreen() {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+    	// We are running in a remote process, so want to have the sub-activity
+    	// sending the result back in the original process.
+        Intent intent = getIntent();
+    	intent.setClass(this, SubActivityScreen.class);
+    	
+        super.onCreate(icicle);
+        
+        boolean kill = intent.getBooleanExtra("kill", false);
+        //Log.i("foo", "RemoteSubActivityScreen pid=" + Process.myPid()
+        //        + " kill=" + kill);
+        
+        if (kill) {
+	        // After finishing initialization, kill the process!  But only if
+	        // this is the first time...
+	        if (icicle == null) {
+		        mHandler.post(new Runnable() {
+		        	public void run() {
+		        		handleBeforeStopping();
+		        		Process.killProcess(Process.myPid());
+		        	}
+		        });
+	        }
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java
new file mode 100644
index 0000000..4b5d468
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Bundle;
+
+import java.util.Map;
+
+public class ResultReceiver extends BroadcastReceiver
+{
+    public ResultReceiver()
+    {
+    }
+
+    public void onReceive(Context context, Intent intent)
+    {
+        setResultCode(3);
+        setResultData("bar");
+        Bundle map = getResultExtras(false);
+        map.remove("remove");
+        map.putString("bar", "them");
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java
new file mode 100644
index 0000000..db523dc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+// These test binders purport to support an interface whose canonical
+// interface name is ServiceTest.SERVICE_LOCAL
+public class ServiceTest extends ActivityTestsBase {
+
+    public static final String SERVICE_LOCAL =
+            "com.android.unit_tests.activity.SERVICE_LOCAL";
+    public static final String SERVICE_LOCAL_GRANTED =
+            "com.android.unit_tests.activity.SERVICE_LOCAL_GRANTED";
+    public static final String SERVICE_LOCAL_DENIED =
+            "com.android.unit_tests.activity.SERVICE_LOCAL_DENIED";
+
+    public static final String REPORT_OBJ_NAME = "report";
+
+    public static final int STARTED_CODE = 1;
+    public static final int DESTROYED_CODE = 2;
+    public static final int SET_REPORTER_CODE = 3;
+    public static final int UNBIND_CODE = 4;
+    public static final int REBIND_CODE = 5;
+
+    public static final int STATE_START_1 = 0;
+    public static final int STATE_START_2 = 1;
+    public static final int STATE_UNBIND = 2;
+    public static final int STATE_DESTROY = 3;
+    public static final int STATE_REBIND = 4;
+    public static final int STATE_UNBIND_ONLY = 5;
+    public int mStartState;
+
+    public IBinder mStartReceiver = new Binder() {
+        @Override
+        protected boolean onTransact(int code, Parcel data, Parcel reply,
+                int flags) throws RemoteException {
+            //Log.i("ServiceTest", "Received code " + code + " in state " + mStartState);
+            if (code == STARTED_CODE) {
+                data.enforceInterface(SERVICE_LOCAL);
+                int count = data.readInt();
+                if (mStartState == STATE_START_1) {
+                    if (count == 1) {
+                        finishGood();
+                    } else {
+                        finishBad("onStart() again on an object when it should have been the first time");
+                    }
+                } else if (mStartState == STATE_START_2) {
+                    if (count == 2) {
+                        finishGood();
+                    } else {
+                        finishBad("onStart() the first time on an object when it should have been the second time");
+                    }
+                } else {
+                    finishBad("onStart() was called when not expected (state="+mStartState+")");
+                }
+                return true;
+            } else if (code == DESTROYED_CODE) {
+                data.enforceInterface(SERVICE_LOCAL);
+                if (mStartState == STATE_DESTROY) {
+                    finishGood();
+                } else {
+                    finishBad("onDestroy() was called when not expected (state="+mStartState+")");
+                }
+                return true;
+            } else if (code == UNBIND_CODE) {
+                data.enforceInterface(SERVICE_LOCAL);
+                if (mStartState == STATE_UNBIND) {
+                    mStartState = STATE_DESTROY;
+                } else if (mStartState == STATE_UNBIND_ONLY) {
+                    finishGood();
+                } else {
+                    finishBad("onUnbind() was called when not expected (state="+mStartState+")");
+                }
+                return true;
+            } else if (code == REBIND_CODE) {
+                data.enforceInterface(SERVICE_LOCAL);
+                if (mStartState == STATE_REBIND) {
+                    finishGood();
+                } else {
+                    finishBad("onRebind() was called when not expected (state="+mStartState+")");
+                }
+                return true;
+            } else {
+                return super.onTransact(code, data, reply, flags);
+            }
+        }
+    };
+
+    public class EmptyConnection implements ServiceConnection {
+        public void onServiceConnected(ComponentName name, IBinder service) {
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+        }
+    }
+
+    public class TestConnection implements ServiceConnection {
+        private final boolean mExpectDisconnect;
+        private final boolean mSetReporter;
+        private boolean mMonitor;
+        private int mCount;
+
+        public TestConnection(boolean expectDisconnect, boolean setReporter) {
+            mExpectDisconnect = expectDisconnect;
+            mSetReporter = setReporter;
+            mMonitor = !setReporter;
+        }
+        
+        void setMonitor(boolean v) {
+            mMonitor = v;
+        }
+
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (mSetReporter) {
+                Parcel data = Parcel.obtain();
+                data.writeInterfaceToken(SERVICE_LOCAL);
+                data.writeStrongBinder(mStartReceiver);
+                try {
+                    service.transact(SET_REPORTER_CODE, data, null, 0);
+                } catch (RemoteException e) {
+                    finishBad("DeadObjectException when sending reporting object");
+                }
+                data.recycle();
+            }
+            
+            if (mMonitor) {
+                mCount++;
+                if (mStartState == STATE_START_1) {
+                    if (mCount == 1) {
+                        finishGood();
+                    } else {
+                        finishBad("onServiceConnected() again on an object when it should have been the first time");
+                    }
+                } else if (mStartState == STATE_START_2) {
+                    if (mCount == 2) {
+                        finishGood();
+                    } else {
+                        finishBad("onServiceConnected() the first time on an object when it should have been the second time");
+                    }
+                } else {
+                    finishBad("onServiceConnected() called unexpectedly");
+                }
+            }
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            if (mMonitor) {
+                if (mStartState == STATE_DESTROY) {
+                    if (mExpectDisconnect) {
+                        finishGood();
+                    } else {
+                        finishBad("onServiceDisconnected() when it shouldn't have been");
+                    }
+                } else {
+                    finishBad("onServiceDisconnected() called unexpectedly");
+                }
+            }
+        }
+    }
+
+    void startExpectResult(Intent service) {
+        startExpectResult(service, new Bundle());
+    }
+
+    void startExpectResult(Intent service, Bundle bundle) {
+        bundle.putIBinder(REPORT_OBJ_NAME, mStartReceiver);
+        boolean success = false;
+        try {
+            //Log.i("foo", "STATE_START_1");
+            mStartState = STATE_START_1;
+            getContext().startService(new Intent(service).putExtras(bundle));
+            waitForResultOrThrow(5 * 1000, "service to start first time");
+            //Log.i("foo", "STATE_START_2");
+            mStartState = STATE_START_2;
+            getContext().startService(new Intent(service).putExtras(bundle));
+            waitForResultOrThrow(5 * 1000, "service to start second time");
+            success = true;
+        } finally {
+            if (!success) {
+                try {
+                    getContext().stopService(service);
+                } catch (Exception e) {
+                    // eat
+                }
+            }
+        }
+        //Log.i("foo", "STATE_DESTROY");
+        mStartState = STATE_DESTROY;
+        getContext().stopService(service);
+        waitForResultOrThrow(5 * 1000, "service to be destroyed");
+    }
+
+    void startExpectNoPermission(Intent service) {
+        try {
+            getContext().startService(service);
+            fail("Expected security exception when starting " + service);
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    void bindExpectResult(Intent service) {
+        TestConnection conn = new TestConnection(true, false);
+        TestConnection conn2 = new TestConnection(false, false);
+        boolean success = false;
+        try {
+            // Expect to see the TestConnection connected.
+            mStartState = STATE_START_1;
+            getContext().bindService(service, conn, 0);
+            getContext().startService(service);
+            waitForResultOrThrow(5 * 1000, "existing connection to receive service");
+
+            // Expect to see the second TestConnection connected.
+            getContext().bindService(service, conn2, 0);
+            waitForResultOrThrow(5 * 1000, "new connection to receive service");
+
+            getContext().unbindService(conn2);
+            success = true;
+        } finally {
+            if (!success) {
+                try {
+                    getContext().stopService(service);
+                    getContext().unbindService(conn);
+                    getContext().unbindService(conn2);
+                } catch (Exception e) {
+                    // eat
+                }
+            }
+        }
+
+        // Expect to see the TestConnection disconnected.
+        mStartState = STATE_DESTROY;
+        getContext().stopService(service);
+        waitForResultOrThrow(5 * 1000, "existing connection to lose service");
+
+        getContext().unbindService(conn);
+        
+        conn = new TestConnection(true, true);
+        success = false;
+        try {
+            // Expect to see the TestConnection connected.
+            conn.setMonitor(true);
+            mStartState = STATE_START_1;
+            getContext().bindService(service, conn, 0);
+            getContext().startService(service);
+            waitForResultOrThrow(5 * 1000, "existing connection to receive service");
+
+            success = true;
+        } finally {
+            if (!success) {
+                try {
+                    getContext().stopService(service);
+                    getContext().unbindService(conn);
+                } catch (Exception e) {
+                    // eat
+                }
+            }
+        }
+
+        // Expect to see the service unbind and then destroyed.
+        conn.setMonitor(false);
+        mStartState = STATE_UNBIND;
+        getContext().stopService(service);
+        waitForResultOrThrow(5 * 1000, "existing connection to lose service");
+
+        getContext().unbindService(conn);
+        
+        conn = new TestConnection(true, true);
+        success = false;
+        try {
+            // Expect to see the TestConnection connected.
+            conn.setMonitor(true);
+            mStartState = STATE_START_1;
+            getContext().bindService(service, conn, 0);
+            getContext().startService(service);
+            waitForResultOrThrow(5 * 1000, "existing connection to receive service");
+
+            success = true;
+        } finally {
+            if (!success) {
+                try {
+                    getContext().stopService(service);
+                    getContext().unbindService(conn);
+                } catch (Exception e) {
+                    // eat
+                }
+            }
+        }
+
+        // Expect to see the service unbind but not destroyed.
+        conn.setMonitor(false);
+        mStartState = STATE_UNBIND_ONLY;
+        getContext().unbindService(conn);
+        waitForResultOrThrow(5 * 1000, "existing connection to unbind service");
+        
+        // Expect to see the service rebound.
+        mStartState = STATE_REBIND;
+        getContext().bindService(service, conn, 0);
+        waitForResultOrThrow(5 * 1000, "existing connection to rebind service");
+        
+        // Expect to see the service unbind and then destroyed.
+        mStartState = STATE_UNBIND;
+        getContext().stopService(service);
+        waitForResultOrThrow(5 * 1000, "existing connection to lose service");
+
+        getContext().unbindService(conn);
+    }
+
+    void bindAutoExpectResult(Intent service) {
+        TestConnection conn = new TestConnection(false, true);
+        boolean success = false;
+        try {
+            conn.setMonitor(true);
+            mStartState = STATE_START_1;
+            getContext().bindService(
+                    service, conn, Context.BIND_AUTO_CREATE);
+            waitForResultOrThrow(5 * 1000, "connection to start and receive service");
+            success = true;
+        } finally {
+            if (!success) {
+                try {
+                    getContext().unbindService(conn);
+                } catch (Exception e) {
+                    // eat
+                }
+            }
+        }
+        mStartState = STATE_UNBIND;
+        getContext().unbindService(conn);
+        waitForResultOrThrow(5 * 1000, "disconnecting from service");
+    }
+
+    void bindExpectNoPermission(Intent service) {
+        TestConnection conn = new TestConnection(false, false);
+        try {
+            getContext().bindService(service, conn, Context.BIND_AUTO_CREATE);
+            fail("Expected security exception when binding " + service);
+        } catch (SecurityException e) {
+            // expected
+        } finally {
+            getContext().unbindService(conn);
+        }
+    }
+
+
+    @MediumTest
+    public void testLocalStartClass() throws Exception {
+        startExpectResult(new Intent(getContext(), LocalService.class));
+    }
+
+    @MediumTest
+    public void testLocalStartAction() throws Exception {
+        startExpectResult(new Intent(SERVICE_LOCAL));
+    }
+
+    @MediumTest
+    public void testLocalBindClass() throws Exception {
+        bindExpectResult(new Intent(getContext(), LocalService.class));
+    }
+
+    @MediumTest
+    public void testLocalBindAction() throws Exception {
+        bindExpectResult(new Intent(SERVICE_LOCAL));
+    }
+
+    @MediumTest
+    public void testLocalBindAutoClass() throws Exception {
+        bindAutoExpectResult(new Intent(getContext(), LocalService.class));
+    }
+
+    @MediumTest
+    public void testLocalBindAutoAction() throws Exception {
+        bindAutoExpectResult(new Intent(SERVICE_LOCAL));
+    }
+
+    @MediumTest
+    public void testLocalStartClassPermissionGranted() throws Exception {
+        startExpectResult(new Intent(getContext(), LocalGrantedService.class));
+    }
+
+    @MediumTest
+    public void testLocalStartActionPermissionGranted() throws Exception {
+        startExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
+    }
+
+    @MediumTest
+    public void testLocalBindClassPermissionGranted() throws Exception {
+        bindExpectResult(new Intent(getContext(), LocalGrantedService.class));
+    }
+
+    @MediumTest
+    public void testLocalBindActionPermissionGranted() throws Exception {
+        bindExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
+    }
+
+    @MediumTest
+    public void testLocalBindAutoClassPermissionGranted() throws Exception {
+        bindAutoExpectResult(new Intent(getContext(), LocalGrantedService.class));
+    }
+
+    @MediumTest
+    public void testLocalBindAutoActionPermissionGranted() throws Exception {
+        bindAutoExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
+    }
+
+    @MediumTest
+    public void testLocalStartClassPermissionDenied() throws Exception {
+        startExpectNoPermission(new Intent(getContext(), LocalDeniedService.class));
+    }
+
+    @MediumTest
+    public void testLocalStartActionPermissionDenied() throws Exception {
+        startExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED));
+    }
+
+    @MediumTest
+    public void testLocalBindClassPermissionDenied() throws Exception {
+        bindExpectNoPermission(new Intent(getContext(), LocalDeniedService.class));
+    }
+
+    @MediumTest
+    public void testLocalBindActionPermissionDenied() throws Exception {
+        bindExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED));
+    }
+
+    @MediumTest
+    public void testLocalUnbindTwice() throws Exception {
+        EmptyConnection conn = new EmptyConnection();
+        getContext().bindService(
+                new Intent(SERVICE_LOCAL_GRANTED), conn, 0);
+        getContext().unbindService(conn);
+        try {
+            getContext().unbindService(conn);
+            fail("No exception thrown on second unbind");
+        } catch (IllegalArgumentException e) {
+            //Log.i("foo", "Unbind exception", e);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java
new file mode 100644
index 0000000..1fa7579
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.activity;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.util.TimeZone;
+
+public class SetTimeZonePermissionsTest extends AndroidTestCase {
+
+    private String[] mZones;
+    private String mCurrentZone;
+    private AlarmManager mAlarm;
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mZones = TimeZone.getAvailableIDs();
+        mCurrentZone = TimeZone.getDefault().getID();
+        mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+    }
+
+    /**
+     * Verify that non-system processes cannot set the time zone.
+     */
+    @LargeTest
+    public void testSetTimeZonePermissions() {
+        /**
+         * Attempt to set several predefined time zones, verifying that the system
+         * system default time zone has not actually changed from its prior state
+         * after each attempt.
+         */
+        int max = (mZones.length > 10) ? mZones.length : 10;
+        assertTrue("No system-defined time zones - test invalid", max > 0);
+
+        for (int i = 0; i < max; i++) {
+            String tz = mZones[i];
+            try {
+                mAlarm.setTimeZone(tz);
+            } catch (SecurityException se) {
+                // Expected failure; no need to handle specially since we're
+                // about to assert that the test invariant holds: no change
+                // to the system time zone.
+            }
+
+            String newZone = TimeZone.getDefault().getID();
+            assertEquals("AlarmManager.setTimeZone() succeeded despite lack of permission",
+                    mCurrentZone,
+                    newZone);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java
new file mode 100644
index 0000000..914b909
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class SubActivityScreen extends Activity {
+    static final int NO_RESULT_MODE = 0;
+    static final int RESULT_MODE = 1;
+    static final int PENDING_RESULT_MODE = 2;
+    static final int FINISH_SUB_MODE = 3;
+
+    static final int CHILD_OFFSET = 1000;
+
+    int mMode;
+
+    public SubActivityScreen() {
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        mMode = getIntent().getIntExtra("mode", mMode);
+        //Log.i("foo", "SubActivityScreen pid=" + Process.myPid()
+        //        + " mode=" + mMode);
+        
+        // Move on to the next thing that will generate a result...  but only
+        // if we are being launched for the first time.
+        if (icicle == null) {
+	        if (mMode == PENDING_RESULT_MODE) {
+	            PendingIntent apr = createPendingResult(1, null,
+	                    Intent.FILL_IN_ACTION);
+	            Intent res = new Intent();
+                res.putExtra("tkey", "tval");
+                res.setAction("test");
+	            try {
+    	            apr.send(this, RESULT_OK, res);
+	            } catch (PendingIntent.CanceledException e) {
+	            }
+	        } else if (mMode < CHILD_OFFSET) {
+	            Intent intent = new Intent();
+	        	intent.setClass(this, SubActivityScreen.class);
+	            intent.putExtra("mode", CHILD_OFFSET+mMode);
+	            //System.out.println("*** Starting from onStart: " + intent);
+	            startActivityForResult(intent, 1);
+	            return;
+	        }
+        }
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle state) {
+        super.onRestoreInstanceState(state);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        //Log.i("foo", "SubActivityScreen pid=" + Process.myPid() + " onResume");
+        
+        if (mMode >= CHILD_OFFSET) {
+        	// Wait a little bit, to give our parent time to kill itself
+        	// if that is something it is into.
+        	try {
+	        	Thread.sleep(500);
+        	} catch (InterruptedException e) {
+        		setResult(RESULT_CANCELED, (new Intent()).setAction("Interrupted!"));
+        		finish();
+        		return;
+        	}
+            //System.out.println("Resuming sub-activity: mode=" + mMode);
+            switch (mMode-CHILD_OFFSET) {
+            case NO_RESULT_MODE:
+                finish();
+                break;
+            case RESULT_MODE:
+                Intent res = new Intent();
+                res.putExtra("tkey", "tval");
+                res.setAction("test");
+                setResult(RESULT_OK, res);
+                finish();
+                break;
+            case FINISH_SUB_MODE:
+                break;
+            }
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode,
+            Intent data) {
+        //Log.i("foo", "SubActivityScreen pid=" + Process.myPid()
+        //        + " onActivityResult: req=" + requestCode
+        //        + " res=" + resultCode);
+
+        // Assume success.
+        setResult(RESULT_OK);
+
+        if (requestCode == 1) {
+            switch (mMode) {
+            case NO_RESULT_MODE:
+            case FINISH_SUB_MODE:
+                if (resultCode != RESULT_CANCELED) {
+                    setResult(RESULT_CANCELED, (new Intent()).setAction(
+                            "Incorrect result code returned: " + resultCode));
+                }
+                break;
+            case RESULT_MODE:
+            case PENDING_RESULT_MODE:
+                if (resultCode != RESULT_OK) {
+                    setResult(RESULT_CANCELED, (new Intent()).setAction(
+                            "Incorrect result code returned: " + resultCode));
+                } else if (data == null) {
+                    setResult(RESULT_CANCELED, (new Intent()).setAction(
+                            "null data returned"));
+                } else if (!("test".equals(data.getAction()))) {
+                    setResult(RESULT_CANCELED, (new Intent()).setAction(
+                            "Incorrect action returned: " + data));
+                } else if (!("tval".equals(data.getStringExtra("tkey")))) {
+                    setResult(RESULT_CANCELED, (new Intent()).setAction(
+                            "Incorrect extras returned: " + data.getExtras()));
+                }
+                break;
+            }
+        } else {
+            setResult(RESULT_CANCELED, (new Intent()).setAction(
+                    "Incorrect request code returned: " + requestCode));
+        }
+
+        finish();
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        handleBeforeStopping();
+    }
+    
+    public void handleBeforeStopping() {
+        if (mMode == FINISH_SUB_MODE) {
+            finishActivity(1);
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java
new file mode 100644
index 0000000..ee02c98
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.test.suitebuilder.annotation.Suppress;
+import android.content.ComponentName;
+
+@Suppress
+public class SubActivityTest extends ActivityTestsBase {
+
+    public void testPendingResult() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.PENDING_RESULT_MODE);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testNoResult() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testResult() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testFinishSub() throws Exception {
+        mIntent.putExtra("component",
+                new ComponentName(getContext(), RemoteSubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testRemoteNoResult() throws Exception {
+        mIntent.putExtra("component",
+                new ComponentName(getContext(), RemoteSubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testRemoteResult() throws Exception {
+        mIntent.putExtra("component",
+                new ComponentName(getContext(), RemoteSubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testRemoteFinishSub() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testRemoteRestartNoResult() throws Exception {
+        mIntent.putExtra("component",
+                new ComponentName(getContext(), RemoteSubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE);
+        mIntent.putExtra("kill", true);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testRemoteRestartResult() throws Exception {
+        mIntent.putExtra("component",
+                new ComponentName(getContext(), RemoteSubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE);
+        mIntent.putExtra("kill", true);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+
+    public void testRemoteRestartFinishSub() throws Exception {
+        mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+        mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE);
+        mIntent.putExtra("kill", true);
+        runLaunchpad(LaunchpadActivity.LAUNCH);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java
new file mode 100644
index 0000000..ec407a9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.Bundle;
+
+public class TestedActivity extends Activity
+{
+    public TestedActivity()
+    {
+    }
+
+    public void onCreate(Bundle icicle)
+    {
+        super.onCreate(icicle);
+    }
+
+    protected void onRestoreInstanceState(Bundle state)
+    {
+        super.onRestoreInstanceState(state);
+    }
+
+    protected void onResume()
+    {
+        super.onResume();
+        Looper.myLooper().myQueue().addIdleHandler(new Idler());
+    }
+
+    protected void onSaveInstanceState(Bundle outState)
+    {
+        super.onSaveInstanceState(outState);
+    }
+
+    protected void onStop()
+    {
+        super.onStop();
+    }
+
+    private Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            setResult(RESULT_OK);
+            finish();
+        }
+    };
+
+    private class Idler implements MessageQueue.IdleHandler
+    {
+        public final boolean queueIdle()
+        {
+            //Message m = Message.obtain();
+            //mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000);
+            setResult(RESULT_OK);
+            finish();
+            return false;
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java
new file mode 100644
index 0000000..4085aa9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.SystemClock;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestedScreen extends Activity
+{
+    public static final String WAIT_BEFORE_FINISH = "TestedScreen.WAIT_BEFORE_FINISH";
+    public static final String DELIVER_RESULT = "TestedScreen.DELIVER_RESULT";
+    public static final String CLEAR_TASK = "TestedScreen.CLEAR_TASK";
+    
+    public TestedScreen() {
+    }
+
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "CREATE tested "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+        if (LaunchpadActivity.FORWARD_RESULT.equals(getIntent().getAction())) {
+            Intent intent = new Intent(getIntent());
+            intent.setAction(DELIVER_RESULT);
+            intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+            startActivity(intent);
+            if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested "
+                    + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+            finish();
+        } else if (DELIVER_RESULT.equals(getIntent().getAction())) {
+            setResult(RESULT_OK, (new Intent()).setAction(
+                    LaunchpadActivity.RETURNED_RESULT));
+            if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested "
+                    + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+            finish();
+        } else if (CLEAR_TASK.equals(getIntent().getAction())) {
+            if (!getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) {
+                launchClearTask();
+            }
+        }
+    }
+
+    protected void onRestoreInstanceState(Bundle state) {
+        super.onRestoreInstanceState(state);
+    }
+
+    protected void onResume() {
+        super.onResume();
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "RESUME tested "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+        if (CLEAR_TASK.equals(getIntent().getAction())) {
+            if (getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) {
+                Looper.myLooper().myQueue().addIdleHandler(new Idler());
+            }
+        } else {
+            Looper.myLooper().myQueue().addIdleHandler(new Idler());
+        }
+    }
+
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+    }
+
+    protected void onStop() {
+        super.onStop();
+        if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "STOP tested "
+                + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+    }
+
+    private void launchClearTask() {
+        Intent intent = new Intent(getIntent()).
+        addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).
+        setClass(this, ClearTop.class);
+        startActivity(intent);
+    }
+    
+    private Handler mHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            if (CLEAR_TASK.equals(getIntent().getAction())) {
+                launchClearTask();
+            } else {
+                if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested "
+                        + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+                setResult(RESULT_OK);
+                finish();
+            }
+        }
+    };
+
+    private class Idler implements MessageQueue.IdleHandler {
+        public final boolean queueIdle() {
+            if (WAIT_BEFORE_FINISH.equals(getIntent().getAction())) {
+                Message m = Message.obtain();
+                mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000);
+            } else if (CLEAR_TASK.equals(getIntent().getAction())) {
+                Message m = Message.obtain();
+                mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000);
+            } else {
+                if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested "
+                        + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+                setResult(RESULT_OK);
+                finish();
+            }
+            return false;
+        }
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java
new file mode 100644
index 0000000..4d5b5e7
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.content;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedValue;
+import com.android.unit_tests.R;
+
+public class ArrayTest extends AndroidTestCase {
+    private Resources mResources;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResources = mContext.getResources();
+    }
+
+    private void checkEntry(int resid, int index, Object res, Object expected) {
+        assertEquals("in resource 0x" + Integer.toHexString(resid)
+                + " at index " + index, expected, res);
+    }
+    
+    private void checkStringArray(int resid, String[] expected) {
+        String[] res = mResources.getStringArray(resid);
+        assertEquals(res.length, expected.length);
+        for (int i=0; i<expected.length; i++) {
+            checkEntry(resid, i, res[i], expected[i]);
+        }
+    }
+    
+    private void checkTextArray(int resid, String[] expected) {
+        CharSequence[] res = mResources.getTextArray(resid);
+        assertEquals(res.length, expected.length);
+        for (int i=0; i<expected.length; i++) {
+            checkEntry(resid, i, res[i], expected[i]);
+        }
+    }
+    
+    private void checkIntArray(int resid, int[] expected) {
+        int[] res = mResources.getIntArray(resid);
+        assertEquals(res.length, expected.length);
+        for (int i=0; i<expected.length; i++) {
+            assertEquals("in resource 0x" + Integer.toHexString(resid)
+                    + " at index " + i, expected[i], res[i]);
+        }
+    }
+    
+    @SmallTest
+    public void testStrings() throws Exception {
+        checkStringArray(R.array.strings, new String[] {"zero", "1", "here"});
+        checkTextArray(R.array.strings, new String[] {"zero", "1", "here"});
+        checkStringArray(R.array.integers, new String[] {null, null, null});
+        checkTextArray(R.array.integers, new String[] {null, null, null});
+    }
+    
+    @SmallTest
+    public void testIntegers() throws Exception {
+        checkIntArray(R.array.strings, new int[] {0, 0, 0});
+        checkIntArray(R.array.integers, new int[] {0, 1, 101});
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/AssetTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/AssetTest.java
new file mode 100644
index 0000000..f38d062
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/AssetTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.content;
+
+import android.content.res.AssetManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class AssetTest extends AndroidTestCase {
+    private AssetManager mAssets;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mAssets = mContext.getAssets();
+    }
+
+    public static void verifyTextAsset(InputStream is) throws IOException {
+        String expectedString = "OneTwoThreeFourFiveSixSevenEightNineTen";
+        byte[] buffer = new byte[10];
+
+        int readCount;
+        int curIndex = 0;
+        while ((readCount = is.read(buffer, 0, buffer.length)) > 0) {
+            for (int i = 0; i < readCount; i++) {
+                assertEquals("At index " + curIndex
+                            + " expected " + expectedString.charAt(curIndex)
+                            + " but found " + ((char) buffer[i]),
+                        buffer[i], expectedString.charAt(curIndex));
+                curIndex++;
+            }
+        }
+
+        readCount = is.read(buffer, 0, buffer.length);
+        assertEquals("Reading end of buffer: expected readCount=-1 but got " + readCount,
+                -1, readCount);
+
+        readCount = is.read(buffer, buffer.length, 0);
+        assertEquals("Reading end of buffer length 0: expected readCount=0 but got " + readCount,
+                0, readCount);
+
+        is.close();
+    }
+
+    @SmallTest
+    public void testReadToEnd() throws Exception {
+        InputStream is = mAssets.open("text.txt");
+        verifyTextAsset(is);
+    }
+
+    // XXX failing
+    public void xxtestListDir() throws Exception {
+        String[] files = mAssets.list("");
+        assertEquals(1, files.length);
+        assertEquals("test.txt", files[0]);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java
new file mode 100644
index 0000000..a63885d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.content;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+import com.android.unit_tests.R;
+
+import java.util.Locale;
+
+public class ConfigTest extends AndroidTestCase {
+
+    private static void checkValue(Resources res, int resId, String expectedValue) {
+        try {
+            String actual = res.getString(resId);
+            assertNotNull("Returned wrong configuration-based simple value: expected <nothing>, got '"
+                    + actual + "' from resource 0x"
+                    + Integer.toHexString(resId),
+                    expectedValue);
+            assertEquals("Returned wrong configuration-based simple value: expected "
+                    + expectedValue + ", got '" + actual + "' from resource 0x"
+                    + Integer.toHexString(resId),
+                    expectedValue, actual);
+        } catch (Resources.NotFoundException e) {
+            assertNull("Resource not found for configuration-based simple value: expecting \""
+                    + expectedValue + "\"",
+                    expectedValue);
+        }
+    }
+
+    private static void checkValue(Resources res, int resId,
+            int[] styleable, String[] expectedValues) {
+        Resources.Theme theme = res.newTheme();
+        TypedArray sa = theme.obtainStyledAttributes(resId, styleable);
+        for (int i = 0; i < styleable.length; i++) {
+            String actual = sa.getString(i);
+            assertEquals("Returned wrong configuration-based style value: expected "
+                    + expectedValues[i] + ", got '" + actual + "' from attr "
+                    + i + " of resource 0x" + Integer.toHexString(resId),
+                    actual, expectedValues[i]);
+        }
+        sa.recycle();
+    }
+
+    public Resources getResources(Configuration config,
+            int mcc, int mnc, int touchscreen, int keyboard, int keysHidden,
+            int navigation, int width, int height) {
+        AssetManager assmgr = new AssetManager();
+        assmgr.addAssetPath(mContext.getPackageResourcePath());
+        DisplayMetrics metrics = new DisplayMetrics();
+        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        Display d = wm.getDefaultDisplay();
+        d.getMetrics(metrics);
+        config.mcc = mcc;
+        config.mnc = mnc;
+        config.touchscreen = touchscreen;
+        config.keyboard = keyboard;
+        config.keyboardHidden = keysHidden;
+        config.navigation = navigation;
+        metrics.widthPixels = width;
+        metrics.heightPixels = height;
+        return new Resources(assmgr, metrics, config);
+    }
+
+    private static void checkPair(Resources res, int[] notResIds,
+            int simpleRes, String simpleString,
+            int bagRes, String bagString) {
+        boolean willHave = true;
+        if (notResIds != null) {
+            for (int i : notResIds) {
+                if (i == simpleRes) {
+                    willHave = false;
+                    break;
+                }
+            }
+        }
+        checkValue(res, simpleRes, willHave ? simpleString : null);
+        checkValue(res, bagRes, R.styleable.TestConfig,
+                new String[]{willHave ? bagString : null});
+    }
+
+    private static void checkAllExcept(Resources res, int[] notResIds) {
+        checkPair(res, notResIds,
+                R.configVarying.simple_default, "only simple default",
+                R.configVarying.bag_default, "only bag default");
+        checkPair(res, notResIds,
+                R.configVarying.simple_mcc111, "only simple mcc111",
+                R.configVarying.bag_mcc111, "only bag mcc111");
+        checkPair(res, notResIds,
+                R.configVarying.simple_mnc222, "only simple mnc222",
+                R.configVarying.bag_mnc222, "only bag mnc222");
+        checkPair(res, notResIds,
+                R.configVarying.simple_xx, "only simple xx",
+                R.configVarying.bag_xx, "only bag xx");
+        checkPair(res, notResIds,
+                R.configVarying.simple_xx_rYY, "only simple xx_rYY",
+                R.configVarying.bag_xx_rYY, "only bag xx_rYY");
+        checkPair(res, notResIds,
+                R.configVarying.simple_notouch, "only simple notouch",
+                R.configVarying.bag_notouch, "only bag notouch");
+        checkPair(res, notResIds,
+                R.configVarying.simple_finger, "only simple finger",
+                R.configVarying.bag_finger, "only bag finger");
+        checkPair(res, notResIds,
+                R.configVarying.simple_stylus, "only simple stylus",
+                R.configVarying.bag_stylus, "only bag stylus");
+        checkPair(res, notResIds,
+                R.configVarying.simple_12key, "only simple 12key",
+                R.configVarying.bag_12key, "only bag 12key");
+        checkPair(res, notResIds,
+                R.configVarying.simple_320x200, "only simple 320x200",
+                R.configVarying.bag_320x200, "only bag 320x200");
+        checkPair(res, notResIds,
+                R.configVarying.simple_480x320, "only simple 480x320",
+                R.configVarying.bag_480x320, "only bag 480x320");
+    }
+    
+    @SmallTest
+    public void testDefaultNavigationMethod() throws Exception {
+        assertEquals(mContext.getResources().getConfiguration().navigation, 
+                Configuration.NAVIGATION_TRACKBALL);
+    }
+
+    @SmallTest
+    public void testAllConfigs() throws Exception {
+        /**
+         * Test a resource that contains a value for each possible single
+         * configuration value.
+         */
+        Configuration config = new Configuration();
+        Resources res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple default");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag default"});
+
+        config.locale = new Locale("xx");
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple xx");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag xx"});
+
+        config.locale = new Locale("xx", "YY");
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple xx-rYY");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag xx-rYY"});
+
+        config = new Configuration();
+        res = getResources(config, 111, 0, 0, 0, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple mcc111");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag mcc111"});
+
+        res = getResources(config, 0, 222, 0, 0, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple mnc222");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag mnc222"});
+
+        res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_NOTOUCH, 0, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple notouch");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag notouch"});
+
+        res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_FINGER, 0, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple finger");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag finger"});
+
+        res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_STYLUS, 0, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple stylus");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag stylus"});
+
+        res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_NOKEYS, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple nokeys");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag nokeys"});
+
+        res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_QWERTY, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple qwerty");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag qwerty"});
+
+        res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_12KEY, 0, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple 12key");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 12key"});
+
+        res = getResources(config, 0, 0, 0, 0, Configuration.KEYBOARDHIDDEN_YES, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple keyshidden");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag keyshidden"});
+
+        res = getResources(config, 0, 0, 0, 0, Configuration.KEYBOARDHIDDEN_NO, 0, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple keysexposed");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag keysexposed"});
+
+        res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_NONAV, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple nonav");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag nonav"});
+
+        res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_DPAD, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple dpad");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag dpad"});
+
+        res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_TRACKBALL, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple trackball");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag trackball"});
+
+        res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_WHEEL, 0, 0);
+        checkValue(res, R.configVarying.simple, "simple wheel");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag wheel"});
+
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 320, 200);
+        checkValue(res, R.configVarying.simple, "simple 320x200");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 320x200"});
+
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 480, 320);
+        checkValue(res, R.configVarying.simple, "simple 480x320");
+        checkValue(res, R.configVarying.bag,
+                R.styleable.TestConfig, new String[]{"bag 480x320"});
+    }
+
+    @MediumTest
+    public void testSingleConfig() throws Exception {
+        /**
+         * Test resources that contain a value for only one possible configuration
+         * value.  XXX This is not yet complete.
+         */
+        Configuration config = new Configuration();
+        Resources res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY});
+
+        config.locale = new Locale("xx");
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+        checkAllExcept(res, null);
+
+        config.locale = new Locale("xx", "YY");
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+        checkAllExcept(res, null);
+
+        config.locale = new Locale("xx", "ZZ");
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+        checkAllExcept(res, new int[]{R.configVarying.simple_xx_rYY});
+
+        config = new Configuration();
+        res = getResources(config, 111, 0, 0, 0, 0, 0, 0, 0);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY});
+
+        res = getResources(config, 0, 222, 0, 0, 0, 0, 0, 0);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY});
+
+        res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_NOTOUCH, 0, 0, 0, 0, 0);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY,
+                R.configVarying.simple_finger,
+                R.configVarying.simple_stylus});
+
+        res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_FINGER, 0, 0, 0, 0, 0);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY,
+                R.configVarying.simple_notouch,
+                R.configVarying.simple_stylus});
+
+        res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_STYLUS, 0, 0, 0, 0, 0);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY,
+                R.configVarying.simple_notouch,
+                R.configVarying.simple_finger});
+
+        res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_12KEY, 0, 0, 0, 0);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY});
+
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 320, 200);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY,
+                R.configVarying.simple_480x320});
+
+        res = getResources(config, 0, 0, 0, 0, 0, 0, 480, 320);
+        checkAllExcept(res, new int[]{
+                R.configVarying.simple_xx,
+                R.configVarying.simple_xx_rYY,
+                R.configVarying.simple_320x200});
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java b/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java
new file mode 100644
index 0000000..80318dc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import junit.framework.TestSuite;
+
+public class ContentTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(ContentTests.class.getName());
+
+        suite.addTestSuite(AssetTest.class);
+        suite.addTestSuite(IntentFilterTest.class);
+        suite.addTest(ResourceTests.suite());
+        suite.addTestSuite(PluralResourcesTest.class);
+        suite.addTestSuite(ConfigTest.class);
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java
new file mode 100644
index 0000000..74a6b8d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.content;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedValue;
+import com.android.unit_tests.R;
+
+public class FractionTest extends AndroidTestCase {
+
+    private Resources mResources;
+    private final TypedValue mValue = new TypedValue();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResources = mContext.getResources();
+    }
+
+    @SmallTest
+    public void testFractions() throws Exception {
+        tryFraction(R.dimen.frac100perc, 1, 1, 1);
+        tryFraction(R.dimen.frac1perc, 1, 1, .01f);
+        tryFraction(R.dimen.fracp1perc, 1, 1, .001f);
+        tryFraction(R.dimen.fracp01perc, 1, 1, .0001f);
+        tryFraction(R.dimen.frac0perc, 1, 1, 0);
+        tryFraction(R.dimen.frac1p1perc, 1, 1, .011f);
+        tryFraction(R.dimen.frac100p1perc, 1, 1, 1.001f);
+        tryFraction(R.dimen.frac25510perc, 1, 1, 255.1f);
+        tryFraction(R.dimen.frac25610perc, 1, 1, 256.1f);
+        tryFraction(R.dimen.frac6553510perc, 1, 1, 65535.1f);
+        tryFraction(R.dimen.frac6553610perc, 1, 1, 65536.1f);
+
+        tryFraction(R.dimen.frac100perc, 100, 1, 100);
+        tryFraction(R.dimen.frac1perc, 100, 1, .01f * 100);
+        tryFraction(R.dimen.fracp1perc, 100, 1, .001f * 100);
+        tryFraction(R.dimen.fracp01perc, 100, 1, .0001f * 100);
+        tryFraction(R.dimen.frac0perc, 100, 1, 0);
+        tryFraction(R.dimen.frac1p1perc, 100, 1, .011f * 100);
+        tryFraction(R.dimen.frac100p1perc, 100, 1, 1.001f * 100);
+        tryFraction(R.dimen.frac25510perc, 100, 1, 255.1f * 100);
+        tryFraction(R.dimen.frac25610perc, 100, 1, 256.1f * 100);
+        tryFraction(R.dimen.frac6553510perc, 100, 1, 65535.1f * 100);
+        tryFraction(R.dimen.frac6553610perc, 100, 1, 65536.1f * 100);
+
+        tryFraction(R.dimen.frac100pperc, 100, 2, 2);
+        tryFraction(R.dimen.frac1pperc, 100, 2, .01f * 2);
+        tryFraction(R.dimen.fracp1pperc, 100, 2, .001f * 2);
+        tryFraction(R.dimen.fracp01pperc, 100, 2, .0001f * 2);
+        tryFraction(R.dimen.frac0pperc, 100, 2, 0);
+        tryFraction(R.dimen.frac1p1pperc, 100, 2, .011f * 2);
+        tryFraction(R.dimen.frac100p1pperc, 100, 2, 1.001f * 2);
+        tryFraction(R.dimen.frac25510pperc, 100, 2, 255.1f * 2);
+        tryFraction(R.dimen.frac25610pperc, 100, 2, 256.1f * 2);
+        tryFraction(R.dimen.frac6553510pperc, 100, 2, 65535.1f * 2);
+        tryFraction(R.dimen.frac6553610pperc, 100, 2, 65536.1f * 2);
+    }
+
+    private void tryFraction(int resid, float base, float pbase, float expected) {
+        mResources.getValue(resid, mValue, true);
+        float res = mValue.getFraction(base, pbase);
+        float diff = Math.abs(expected - res);
+        float prec = expected * 1e-4f;
+        if (prec < 1e-5f) {
+            prec = 1e-5f;
+        }
+        //System.out.println(
+        //    "Res 0x" + Integer.toHexString(resid) + ": got=" + res
+        //    + ", expected=" + expected + ", diff=" + diff);
+        assertFalse("Expecting value " + expected + " got " + res
+                            + ": in resource 0x" + Integer.toHexString(resid)
+                            + " " + mValue,
+                diff > prec);
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java
new file mode 100644
index 0000000..0335b9d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.content;
+
+import android.content.IntentFilter;
+import android.test.suitebuilder.annotation.SmallTest;
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+import static android.os.PatternMatcher.PATTERN_PREFIX;
+import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+import android.net.Uri;
+import android.util.StringBuilderPrinter;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+
+public class IntentFilterTest extends TestCase {
+
+    public static class Match extends IntentFilter {
+        Match(String[] actions, String[] categories, String[] mimeTypes,
+                String[] schemes, String[] authorities, String[] ports) {
+            if (actions != null) {
+                for (int i = 0; i < actions.length; i++) {
+                    addAction(actions[i]);
+                }
+            }
+            if (categories != null) {
+                for (int i = 0; i < categories.length; i++) {
+                    addCategory(categories[i]);
+                }
+            }
+            if (mimeTypes != null) {
+                for (int i = 0; i < mimeTypes.length; i++) {
+                    try {
+                        addDataType(mimeTypes[i]);
+                    } catch (IntentFilter.MalformedMimeTypeException e) {
+                        throw new RuntimeException("Bad mime type", e);
+                    }
+                }
+            }
+            if (schemes != null) {
+                for (int i = 0; i < schemes.length; i++) {
+                    addDataScheme(schemes[i]);
+                }
+            }
+            if (authorities != null) {
+                for (int i = 0; i < authorities.length; i++) {
+                    addDataAuthority(authorities[i],
+                            ports != null ? ports[i] : null);
+                }
+            }
+        }
+
+        Match(String[] actions, String[] categories, String[] mimeTypes,
+                String[] schemes, String[] authorities, String[] ports,
+                String[] paths, int[] pathTypes) {
+            this(actions, categories, mimeTypes, schemes, authorities, ports);
+            if (paths != null) {
+                for (int i = 0; i < paths.length; i++) {
+                    addDataPath(paths[i], pathTypes[i]);
+                }
+            }
+        }
+    }
+
+    public static class MatchCondition {
+        public final int result;
+        public final String action;
+        public final String mimeType;
+        public final Uri data;
+        public final String[] categories;
+
+        public MatchCondition(int _result, String _action, String[] _categories,
+                String _mimeType, String _data) {
+            result = _result;
+            action = _action;
+            mimeType = _mimeType;
+            data = _data != null ? Uri.parse(_data) : null;
+            categories = _categories;
+        }
+    }
+
+    public static void checkMatches(IntentFilter filter,
+            MatchCondition[] results) {
+        for (int i = 0; i < results.length; i++) {
+            MatchCondition mc = results[i];
+            HashSet<String> categories = null;
+            if (mc.categories != null) {
+                for (int j = 0; j < mc.categories.length; j++) {
+                    if (categories == null) {
+                        categories = new HashSet<String>();
+                    }
+                    categories.add(mc.categories[j]);
+                }
+            }
+            int result = filter.match(mc.action, mc.mimeType,
+                    mc.data != null ? mc.data.getScheme() : null, mc.data,
+                    categories, "test");
+            if ( (result & IntentFilter.MATCH_CATEGORY_MASK)
+                    != (mc.result & IntentFilter.MATCH_CATEGORY_MASK) ) {
+                StringBuilder msg = new StringBuilder();
+                msg.append("Error matching against IntentFilter:\n");
+                filter.dump(new StringBuilderPrinter(msg), "    ");
+                msg.append("Match action: ");
+                msg.append(mc.action);
+                msg.append("\nMatch mimeType: ");
+                msg.append(mc.mimeType);
+                msg.append("\nMatch data: ");
+                msg.append(mc.data);
+                msg.append("\nMatch categories: ");
+                if (mc.categories != null) {
+                    for (int j = 0; j < mc.categories.length; j++) {
+                        if (j > 0) msg.append(", ");
+                        msg.append(mc.categories[j]);
+                    }
+                }
+                msg.append("\nExpected result: 0x");
+                msg.append(Integer.toHexString(mc.result));
+                msg.append(", got result: 0x");
+                msg.append(Integer.toHexString(result));
+                throw new RuntimeException(msg.toString());
+            }
+        }
+    }
+
+    @SmallTest
+    public void testActions() throws Exception {
+        IntentFilter filter = new Match(
+                new String[]{"action1"}, null, null, null, null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action1",
+                        null, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_ACTION, "action2",
+                        null, null, null),
+        });
+
+        filter = new Match(
+                new String[]{"action1", "action2"},
+                null, null, null, null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action1",
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action2",
+                        null, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_ACTION, "action3",
+                        null, null, null),
+        });
+    }
+
+    @SmallTest
+    public void testCategories() throws Exception {
+        IntentFilter filter = new Match(
+                null, new String[]{"category1"}, null, null, null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+                        new String[]{"category1"}, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null,
+                        new String[]{"category2"}, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null,
+                        new String[]{"category1", "category2"}, null, null),
+        });
+
+        filter = new Match(
+                null, new String[]{"category1", "category2"}, null, null,
+                null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+                        new String[]{"category1"}, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+                        new String[]{"category2"}, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+                        new String[]{"category1", "category2"}, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null,
+                        new String[]{"category3"}, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null,
+                        new String[]{"category1", "category2", "category3"},
+                        null, null),
+        });
+    }
+
+    @SmallTest
+    public void testMimeTypes() throws Exception {
+        IntentFilter filter = new Match(
+                null, null, new String[]{"which1/what1"}, null, null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/what1", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/*", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "*/*", null),
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+                        "which2/what2", null),
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+                        "which2/*", null),
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+                        "which1/what2", null),
+        });
+
+        filter = new Match(null, null,
+                new String[]{"which1/what1", "which2/what2"}, null, null,
+                null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/what1", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/*", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "*/*", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which2/what2", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which2/*", null),
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+                        "which1/what2", null),
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+                        "which3/what3", null),
+        });
+
+        filter = new Match(null, null,
+                new String[]{"which1/*"}, null, null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/what1", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/*", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "*/*", null),
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+                        "which2/what2", null),
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+                        "which2/*", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/what2", null),
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+                        "which3/what3", null),
+        });
+
+        filter = new Match(null, null,
+                new String[]{"*/*"}, null, null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_TYPE, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/what1", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/*", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "*/*", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which2/what2", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which2/*", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which1/what2", null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+                        "which3/what3", null),
+        });
+    }
+
+    @SmallTest
+    public void testSchemes() throws Exception {
+        IntentFilter filter = new Match(null, null, null,
+                new String[]{"scheme1"}, null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null,
+                        null, null, "scheme1:foo"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme2:foo"),
+        });
+
+        filter = new Match(null, null, null,
+                new String[]{"scheme1", "scheme2"}, null, null);
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null,
+                        null, null, "scheme1:foo"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null,
+                        null, null, "scheme2:foo"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme3:foo"),
+        });
+    }
+
+    @SmallTest
+    public void testAuthorities() throws Exception {
+        IntentFilter filter = new Match(null, null, null,
+                new String[]{"scheme1"},
+                new String[]{"authority1"}, new String[]{null});
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1:foo"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null,
+                        null, null, "scheme1://authority1/"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1://authority2/"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null,
+                        null, null, "scheme1://authority1:100/"),
+        });
+
+        filter = new Match(null, null, null, new String[]{"scheme1"},
+                new String[]{"authority1"}, new String[]{"100"});
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1:foo"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1://authority1/"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1://authority2/"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PORT, null,
+                        null, null, "scheme1://authority1:100/"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1://authority1:200/"),
+        });
+
+        filter = new Match(null, null, null, new String[]{"scheme1"},
+                new String[]{"authority1", "authority2"},
+                new String[]{"100", null});
+        checkMatches(filter, new MatchCondition[]{
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, null),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1:foo"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1://authority1/"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null,
+                        null, null, "scheme1://authority2/"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PORT, null,
+                        null, null, "scheme1://authority1:100/"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme1://authority1:200/"),
+        });
+    }
+
+    @SmallTest
+    public void testPaths() throws Exception {
+        IntentFilter filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, null,
+                new String[]{"/literal1", "/2literal"},
+                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_PATH, null,
+                        null, null, "scheme://authority/literal1"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/2literal"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/literal"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/literal12"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, null,
+                new String[]{"/literal1", "/2literal"},
+                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_PATH, null,
+                        null, null, "scheme://authority/literal1"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/2literal"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/literal"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/literal12"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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_PATH, null,
+                        null, null, "scheme://authority/literal1"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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_PATH, null,
+                        null, null, "scheme://authority/literal1"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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_PATH, null,
+                        null, null, "scheme://authority/ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a1b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a11b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a2b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a1bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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_PATH, null,
+                        null, null, "scheme://authority/a1"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a11"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a1b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a11"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a2"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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_PATH, null,
+                        null, null, "scheme://authority/ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a.b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a..b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a2b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a.bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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_PATH, null,
+                        null, null, "scheme://authority/ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a.b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a.1b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a2b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a.bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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_PATH, null,
+                        null, null, "scheme://authority/ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a.b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a.1b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a2b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a.bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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://authority/ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a.*b"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a1*b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a2b"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a.bc"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/"),
+        });
+        filter = new Match(null, null, null,
+                new String[]{"scheme"}, new String[]{"authority"}, 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://authority/ab"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a.*"),
+                new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+                        null, null, "scheme://authority/a1*"),
+                new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+                        null, null, "scheme://authority/a1b"),
+        });
+    }
+
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java
new file mode 100644
index 0000000..c3d1478
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.content;
+
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedValue;
+import android.util.Log;
+import com.android.unit_tests.R;
+
+import junit.framework.Assert;
+
+import java.util.Locale;
+
+public class PluralResourcesTest extends AndroidTestCase {
+    private static final String TAG = "PluralResourcesTest";
+
+    private Resources mResources;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResources = mContext.getResources();
+    }
+
+    Resources resourcesForLanguage(String lang) {
+        Configuration config = new Configuration();
+        config.updateFrom(mResources.getConfiguration());
+        config.locale = new Locale(lang);
+        return new Resources(mResources.getAssets(), mResources.getDisplayMetrics(), config);
+    }
+
+    @SmallTest
+    public void testPlurals() throws Exception {
+        CharSequence cs;
+        Resources res = resourcesForLanguage("en");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 0);
+        Log.d(TAG, "english 0 cs=" + cs);
+        Assert.assertEquals(cs.toString(), "Some dogs");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 1);
+        Log.d(TAG, "english 1 cs=" + cs);
+        Assert.assertEquals(cs.toString(), "A dog");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 2);
+        Assert.assertEquals(cs.toString(), "Some dogs");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 5);
+        Assert.assertEquals(cs.toString(), "Some dogs");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 500);
+        Assert.assertEquals(cs.toString(), "Some dogs");
+    }
+
+    @SmallTest
+    public void testCzech() throws Exception {
+        CharSequence cs;
+        Resources res = resourcesForLanguage("cs");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 0);
+        Log.d(TAG, "czech 0 cs=" + cs);
+        Assert.assertEquals(cs.toString(), "Some Czech dogs");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 1);
+        Log.d(TAG, "czech 1 cs=" + cs);
+        Assert.assertEquals(cs.toString(), "A Czech dog");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 2);
+        Log.d(TAG, "czech 2 cs=" + cs);
+        Assert.assertEquals(cs.toString(), "Few Czech dogs");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 5);
+        Assert.assertEquals(cs.toString(), "Some Czech dogs");
+
+        cs = res.getQuantityText(R.plurals.plurals_test, 500);
+        Assert.assertEquals(cs.toString(), "Some Czech dogs");
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java
new file mode 100644
index 0000000..44098cc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.content;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedValue;
+import com.android.unit_tests.R;
+
+public class PrimitiveTest extends AndroidTestCase {
+    private Resources mResources;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResources = mContext.getResources();
+    }
+
+    private void tryEnum(int resid, int expected) {
+        TypedArray sa =
+                mContext.obtainStyledAttributes(resid, R.styleable.EnumStyle);
+        int value = sa.getInt(R.styleable.EnumStyle_testEnum, -1);
+        sa.recycle();
+
+        assertEquals("Expecting value " + expected + " got " + value
+                + ": in resource 0x" + Integer.toHexString(resid),
+                expected, value);
+    }
+
+    @SmallTest
+    public void testEnum() throws Exception {
+        tryEnum(R.style.TestEnum1, 1);
+        tryEnum(R.style.TestEnum2, 2);
+        tryEnum(R.style.TestEnum10, 10);
+        tryEnum(R.style.TestEnum1_EmptyInherit, 1);
+    }
+
+    private void tryFlag(int resid, int expected) {
+        TypedArray sa =
+                mContext.obtainStyledAttributes(resid, R.styleable.FlagStyle);
+        int value = sa.getInt(R.styleable.FlagStyle_testFlags, -1);
+        sa.recycle();
+
+        assertEquals("Expecting value " + expected + " got " + value
+                + ": in resource 0x" + Integer.toHexString(resid),
+                expected, value);
+    }
+
+    @SmallTest
+    public void testFlags() throws Exception {
+        tryFlag(R.style.TestFlag1, 0x1);
+        tryFlag(R.style.TestFlag2, 0x2);
+        tryFlag(R.style.TestFlag31, 0x40000000);
+        tryFlag(R.style.TestFlag1And2, 0x3);
+        tryFlag(R.style.TestFlag1And2And31, 0x40000003);
+    }
+
+    private void tryBoolean(int resid, boolean expected) {
+        TypedValue v = new TypedValue();
+        mContext.getResources().getValue(resid, v, true);
+        assertEquals(TypedValue.TYPE_INT_BOOLEAN, v.type);
+        assertEquals("Expecting boolean value " + expected + " got " + v
+                + " from TypedValue: in resource 0x" + Integer.toHexString(resid),
+                expected, v.data != 0);
+        assertEquals("Expecting boolean value " + expected + " got " + v
+                + " from getBoolean(): in resource 0x" + Integer.toHexString(resid),
+                expected, mContext.getResources().getBoolean(resid));
+    }
+
+    @SmallTest
+    public void testBoolean() throws Exception {
+        tryBoolean(R.bool.trueRes, true);
+        tryBoolean(R.bool.falseRes, false);
+    }
+
+    private void tryString(int resid, String expected) {
+        TypedValue v = new TypedValue();
+        mContext.getResources().getValue(resid, v, true);
+        assertEquals(TypedValue.TYPE_STRING, v.type);
+        assertEquals("Expecting string value " + expected + " got " + v
+                + ": in resource 0x" + Integer.toHexString(resid),
+                expected, v.string);
+    }
+
+    @SmallTest
+    public void testStringCoerce() throws Exception {
+        tryString(R.string.coerceIntegerToString, "100");
+        tryString(R.string.coerceBooleanToString, "true");
+        tryString(R.string.coerceColorToString, "#fff");
+        tryString(R.string.coerceFloatToString, "100.0");
+        tryString(R.string.coerceDimensionToString, "100px");
+        tryString(R.string.coerceFractionToString, "100%");
+    }
+
+    private static void checkString(int resid, String actual, String expected) {
+        assertEquals("Expecting string value \"" + expected + "\" got \""
+                + actual + "\" in resources 0x" + Integer.toHexString(resid),
+                expected, actual);
+    }
+
+    @SmallTest
+    public void testFormattedString() throws Exception {
+        // Make sure the regular one doesn't format anything
+        checkString(R.string.formattedStringNone,
+                mResources.getString(R.string.formattedStringNone),
+                "Format[]");
+        checkString(R.string.formattedStringOne,
+                mResources.getString(R.string.formattedStringOne),
+                "Format[%d]");
+        checkString(R.string.formattedStringTwo,
+                mResources.getString(R.string.formattedStringTwo),
+                "Format[%3$d,%2$s]");
+        // Make sure the formatted one works
+        checkString(R.string.formattedStringNone,
+                mResources.getString(R.string.formattedStringNone),
+                "Format[]");
+        checkString(R.string.formattedStringOne,
+                mResources.getString(R.string.formattedStringOne, 42),
+                "Format[42]");
+        checkString(R.string.formattedStringTwo,
+                mResources.getString(R.string.formattedStringTwo, "unused", "hi", 43),
+                "Format[43,hi]");
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java
new file mode 100644
index 0000000..1786dc4
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.content;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.unit_tests.R;
+
+import java.io.InputStream;
+
+public class RawResourceTest extends AndroidTestCase {
+    private Resources mResources;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResources = mContext.getResources();
+    }
+
+    @SmallTest
+    public void testReadToEnd() throws Exception {
+        InputStream is = mResources.openRawResource(R.raw.text);
+        AssetTest.verifyTextAsset(is);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java
new file mode 100644
index 0000000..2a56243
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.content;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.unit_tests.R;
+
+public class ResourceNameTest extends AndroidTestCase {
+
+    @SmallTest
+    public void testGetResourceName() {
+        Resources res = mContext.getResources();
+        
+        String fullName = res.getResourceName(R.configVarying.simple);
+        assertEquals("com.android.unit_tests:configVarying/simple", fullName);
+        
+        String packageName = res.getResourcePackageName(R.configVarying.simple);
+        assertEquals("com.android.unit_tests", packageName);
+        
+        String typeName = res.getResourceTypeName(R.configVarying.simple);
+        assertEquals("configVarying", typeName);
+        
+        String entryName = res.getResourceEntryName(R.configVarying.simple);
+        assertEquals("simple", entryName);
+    }
+    
+    @SmallTest
+    public void testGetResourceIdentifier() {
+        Resources res = mContext.getResources();
+        int resid = res.getIdentifier(
+                "com.android.unit_tests:configVarying/simple",
+                null, null);
+        assertEquals(R.configVarying.simple, resid);
+        
+        resid = res.getIdentifier("configVarying/simple", null,
+                "com.android.unit_tests");
+        assertEquals(R.configVarying.simple, resid);
+        
+        resid = res.getIdentifier("simple", "configVarying",
+                "com.android.unit_tests");
+        assertEquals(R.configVarying.simple, resid);
+    }    
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java
new file mode 100644
index 0000000..943941e
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import junit.framework.TestSuite;
+
+public class ResourceTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(ResourceTests.class.getName());
+
+        suite.addTestSuite(FractionTest.class);
+        suite.addTestSuite(PrimitiveTest.class);
+        suite.addTestSuite(ArrayTest.class);
+        suite.addTestSuite(ConfigTest.class);
+        suite.addTestSuite(RawResourceTest.class);
+        suite.addTestSuite(ResourceNameTest.class);
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java
new file mode 100644
index 0000000..e8001e34
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+
+public class BitmapTest extends TestCase {
+
+    @SmallTest
+    public void testBasic() throws Exception {
+        Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+        Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+        Bitmap bm3 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_4444);
+
+        assertTrue("mutability", bm1.isMutable());
+        assertTrue("mutability", bm2.isMutable());
+        assertTrue("mutability", bm3.isMutable());
+
+        assertEquals("width", 100, bm1.getWidth());
+        assertEquals("width", 100, bm2.getWidth());
+        assertEquals("width", 100, bm3.getWidth());
+
+        assertEquals("rowbytes", 400, bm1.getRowBytes());
+        assertEquals("rowbytes", 200, bm2.getRowBytes());
+        assertEquals("rowbytes", 200, bm3.getRowBytes());
+        
+        assertEquals("height", 200, bm1.getHeight());
+        assertEquals("height", 200, bm2.getHeight());
+        assertEquals("height", 200, bm3.getHeight());
+
+        assertTrue("hasAlpha", bm1.hasAlpha());
+        assertFalse("hasAlpha", bm2.hasAlpha());
+        assertTrue("hasAlpha", bm3.hasAlpha());
+        
+        assertTrue("getConfig", bm1.getConfig() == Bitmap.Config.ARGB_8888);
+        assertTrue("getConfig", bm2.getConfig() == Bitmap.Config.RGB_565);
+        assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_4444);
+    }
+
+    @SmallTest
+    public void testMutability() throws Exception {
+        Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+        Bitmap bm2 = Bitmap.createBitmap(new int[100 * 200], 100, 200,
+                                         Bitmap.Config.ARGB_8888);
+
+        assertTrue("mutability", bm1.isMutable());
+        assertFalse("mutability", bm2.isMutable());
+
+        bm1.eraseColor(0);
+
+        try {
+            bm2.eraseColor(0);
+            fail("eraseColor should throw exception");
+        } catch (IllegalStateException ex) {
+            // safe to catch and ignore this
+        }
+    }
+
+    @SmallTest
+    public void testGetPixelsWithAlpha() throws Exception {
+        int[] colors = new int[100];
+        for (int i = 0; i < 100; i++) {
+            colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
+        }
+
+        Bitmap bm = Bitmap.createBitmap(colors, 10, 10,
+                                        Bitmap.Config.ARGB_8888);
+
+        int[] pixels = new int[100];
+        bm.getPixels(pixels, 0, 10, 0, 0, 10, 10);
+        for (int i = 0; i < 100; i++) {
+            int p = bm.getPixel(i % 10, i / 10);
+            assertEquals("getPixels", p, pixels[i]);
+        }
+
+        for (int i = 0; i < 100; i++) {
+            int p = bm.getPixel(i % 10, i / 10);
+            assertEquals("getPixel", p, colors[i]);
+            assertEquals("pixel value", p,
+                         ((0xFF << 24) | (i << 16) | (i << 8) | i));
+        }
+
+    }
+
+    @SmallTest
+    public void testGetPixelsWithoutAlpha() throws Exception {
+        int[] colors = new int[100];
+        for (int i = 0; i < 100; i++) {
+            colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
+        }
+
+        Bitmap bm = Bitmap.createBitmap(colors, 10, 10, Bitmap.Config.RGB_565);
+
+        int[] pixels = new int[100];
+        bm.getPixels(pixels, 0, 10, 0, 0, 10, 10);
+        for (int i = 0; i < 100; i++) {
+            int p = bm.getPixel(i % 10, i / 10);
+            assertEquals("getPixels", p, pixels[i]);
+        }
+    }
+
+    @SmallTest
+    public void testSetPixelsWithAlpha() throws Exception {
+        int[] colors = new int[100];
+        for (int i = 0; i < 100; i++) {
+            colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
+        }
+
+        Bitmap.Config config = Bitmap.Config.ARGB_8888;
+        Bitmap bm1 = Bitmap.createBitmap(colors, 10, 10, config);
+        Bitmap bm2 = Bitmap.createBitmap(10, 10, config);
+
+        for (int i = 0; i < 100; i++) {
+            bm2.setPixel(i % 10, i / 10, colors[i]);
+        }
+
+        for (int i = 0; i < 100; i++) {
+            assertEquals("setPixel",
+                    bm1.getPixel(i % 10, i / 10), bm2.getPixel(i % 10, i / 10));
+        }
+
+        for (int i = 0; i < 100; i++) {
+            assertEquals("setPixel value",
+                         bm1.getPixel(i % 10, i / 10), colors[i]);
+        }
+    }
+
+    @SmallTest
+    public void testSetPixelsWithoutAlpha() throws Exception {
+        int[] colors = new int[100];
+        for (int i = 0; i < 100; i++) {
+            colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
+        }
+
+        Bitmap.Config config = Bitmap.Config.RGB_565;
+        Bitmap bm1 = Bitmap.createBitmap(colors, 10, 10, config);
+        Bitmap bm2 = Bitmap.createBitmap(10, 10, config);
+
+        for (int i = 0; i < 100; i++) {
+            bm2.setPixel(i % 10, i / 10, colors[i]);
+        }
+
+        for (int i = 0; i < 100; i++) {
+            assertEquals("setPixel", bm1.getPixel(i % 10, i / 10),
+                         bm2.getPixel(i % 10, i / 10));
+        }
+    }
+
+    private static int computePrePostMul(int alpha, int comp) {
+        if (alpha == 0) {
+            return 0;
+        }
+        int premul = Math.round(alpha * comp / 255.f);
+        int unpre = Math.round(255.0f * premul / alpha);
+        return unpre;
+    }
+
+    @SmallTest
+    public void testSetPixelsWithNonOpaqueAlpha() throws Exception {
+        int[] colors = new int[256];
+        for (int i = 0; i < 256; i++) {
+            colors[i] = (i << 24) | (0xFF << 16) | (0x80 << 8) | 0;
+        }
+        
+        Bitmap.Config config = Bitmap.Config.ARGB_8888;
+
+        // create a bitmap with the color array specified
+        Bitmap bm1 = Bitmap.createBitmap(colors, 16, 16, config);
+        
+        // create a bitmap with no colors, but then call setPixels
+        Bitmap bm2 = Bitmap.createBitmap(16, 16, config);
+        bm2.setPixels(colors, 0, 16, 0, 0, 16, 16);
+
+        // now check that we did a good job returning the unpremultiplied alpha
+        final int tolerance = 1;
+        for (int i = 0; i < 256; i++) {
+            int c0 = colors[i];
+            int c1 = bm1.getPixel(i % 16, i / 16);
+            int c2 = bm2.getPixel(i % 16, i / 16);
+            
+            // these two should always be identical
+            assertEquals("getPixel", c1, c2);
+            
+            // comparing the original (c0) with the returned color is tricky,
+            // since it gets premultiplied during the set(), and unpremultiplied
+            // by the get().
+            int a0 = Color.alpha(c0);
+            int a1 = Color.alpha(c1);
+            assertEquals("alpha", a0, a1);
+            
+            int r0 = Color.red(c0);
+            int r1 = Color.red(c1);
+            int rr = computePrePostMul(a0, r0);
+            assertTrue("red", Math.abs(rr - r1) <= tolerance);
+            
+            int g0 = Color.green(c0);
+            int g1 = Color.green(c1);
+            int gg = computePrePostMul(a0, g0);
+            assertTrue("green", Math.abs(gg - g1) <= tolerance);
+            
+            int b0 = Color.blue(c0);
+            int b1 = Color.blue(c1);
+            int bb = computePrePostMul(a0, b0);
+            assertTrue("blue", Math.abs(bb - b1) <= tolerance);
+            
+            if (false) {
+                int cc = Color.argb(a0, rr, gg, bb);
+                android.util.Log.d("skia", "original " + Integer.toHexString(c0) +
+                                " set+get " + Integer.toHexString(c1) +
+                               " local " + Integer.toHexString(cc));
+            }
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java
new file mode 100644
index 0000000..a8b6b9a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.graphics;
+
+import junit.framework.TestSuite;
+
+public class GraphicsTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(GraphicsTests.class.getName());
+
+        suite.addTestSuite(BitmapTest.class);
+        suite.addTestSuite(TypefaceTest.class);
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java
new file mode 100644
index 0000000..5c40e6f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.graphics;
+
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+
+public class TypefaceTest extends TestCase {
+
+    // create array of all std faces
+    private final Typeface[] mFaces = new Typeface[] {
+        Typeface.create(Typeface.SANS_SERIF, 0),
+        Typeface.create(Typeface.SANS_SERIF, 1),
+        Typeface.create(Typeface.SERIF, 0),
+        Typeface.create(Typeface.SERIF, 1),
+        Typeface.create(Typeface.SERIF, 2),
+        Typeface.create(Typeface.SERIF, 3),
+        Typeface.create(Typeface.MONOSPACE, 0)
+    };
+    
+    @SmallTest
+    public void testBasic() throws Exception {
+        assertTrue("basic", Typeface.DEFAULT != null);
+        assertTrue("basic", Typeface.DEFAULT_BOLD != null);
+        assertTrue("basic", Typeface.SANS_SERIF != null);
+        assertTrue("basic", Typeface.SERIF != null);
+        assertTrue("basic", Typeface.MONOSPACE != null);
+    }
+    
+    @SmallTest
+    public void testUnique() throws Exception {
+        final int n = mFaces.length;
+        for (int i = 0; i < n; i++) {
+            for (int j = i + 1; j < n; j++) {
+                assertTrue("unique", mFaces[i] != mFaces[j]);
+            }
+        }
+    }
+
+    @SmallTest
+    public void testStyles() throws Exception {
+        assertTrue("style", mFaces[0].getStyle() == Typeface.NORMAL);
+        assertTrue("style", mFaces[1].getStyle() == Typeface.BOLD);
+        assertTrue("style", mFaces[2].getStyle() == Typeface.NORMAL);
+        assertTrue("style", mFaces[3].getStyle() == Typeface.BOLD);
+        assertTrue("style", mFaces[4].getStyle() == Typeface.ITALIC);
+        assertTrue("style", mFaces[5].getStyle() == Typeface.BOLD_ITALIC);
+        assertTrue("style", mFaces[6].getStyle() == Typeface.NORMAL);
+    }
+
+    @MediumTest
+    public void testUniformY() throws Exception {
+        Paint p = new Paint();
+        final int n = mFaces.length;
+        for (int i = 1; i <= 36; i++) {
+            p.setTextSize(i);
+            float ascent = 0;
+            float descent = 0;
+            for (int j = 0; j < n; j++) {
+                p.setTypeface(mFaces[j]);
+                Paint.FontMetrics fm = p.getFontMetrics();
+                if (j == 0) {
+                    ascent = fm.ascent;
+                    descent = fm.descent;
+                } else {
+                    assertTrue("fontMetrics", fm.ascent == ascent);
+                    assertTrue("fontMetrics", fm.descent == descent);
+                }
+            }
+        }
+    }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl
new file mode 100644
index 0000000..62c75a5
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl
@@ -0,0 +1,20 @@
+/* //device/apps/AndroidTests/src/com.android.unit_tests/AidlTest.aidl
+**
+** Copyright 2007, 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.unit_tests.os;
+
+parcelable AidlTest.TestParcelable;
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java
new file mode 100644
index 0000000..52e666d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.os;
+
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.google.android.collect.Lists;
+import junit.framework.TestCase;
+
+import java.util.List;
+
+public class AidlTest extends TestCase {
+
+    private IAidlTest mRemote;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        AidlObject mLocal = new AidlObject();
+        mRemote = IAidlTest.Stub.asInterface(mLocal);
+    }
+
+    private static boolean check(TestParcelable p, int n, String s) {
+        return p.mAnInt == n &&
+                ((s == null && p.mAString == null) || s.equals(p.mAString));
+    }
+
+    public static class TestParcelable implements Parcelable {
+        public int mAnInt;
+        public String mAString;
+
+        public TestParcelable() {
+        }
+
+        public TestParcelable(int i, String s) {
+            mAnInt = i;
+            mAString = s;
+        }
+
+        public int describeContents() {
+            return 0;
+        }
+
+        public void writeToParcel(Parcel parcel, int flags) {
+            parcel.writeInt(mAnInt);
+            parcel.writeString(mAString);
+        }
+
+        public void readFromParcel(Parcel parcel) {
+            mAnInt = parcel.readInt();
+            mAString = parcel.readString();
+        }
+
+        public static final Parcelable.Creator<TestParcelable> CREATOR
+                = new Parcelable.Creator<TestParcelable>() {
+            public TestParcelable createFromParcel(Parcel parcel) {
+                return new TestParcelable(parcel.readInt(),
+                        parcel.readString());
+            }
+
+            public TestParcelable[] newArray(int size) {
+                return new TestParcelable[size];
+            }
+        };
+
+        public String toString() {
+            return super.toString() + " {" + mAnInt + "/" + mAString + "}";
+        }
+    }
+
+    private static class AidlObject extends IAidlTest.Stub {
+        public IInterface queryLocalInterface(String descriptor) {
+            // overriding this to return null makes asInterface always
+            // generate a proxy
+            return null;
+        }
+
+        public int intMethod(int a) {
+            return a;
+        }
+
+        public TestParcelable parcelableIn(TestParcelable p) {
+            p.mAnInt++;
+            return p;
+        }
+
+        public TestParcelable parcelableOut(TestParcelable p) {
+            p.mAnInt = 44;
+            return p;
+        }
+
+        public TestParcelable parcelableInOut(TestParcelable p) {
+            p.mAnInt++;
+            return p;
+        }
+
+        public TestParcelable listParcelableLonger(List<TestParcelable> list, int index) {
+            list.add(list.get(index));
+            return list.get(index);
+        }
+
+        public int listParcelableShorter(List<TestParcelable> list, int index) {
+            list.remove(index);
+            return list.size();
+        }
+
+        public boolean[] booleanArray(boolean[] a0, boolean[] a1, boolean[] a2) {
+            for (int i = 0; i < a0.length && i < a2.length; i++) {
+                a2[i] = a0[i];
+            }
+            for (int i = 0; i < a0.length && i < a1.length; i++) {
+                a1[i] = a0[i];
+            }
+            return a0;
+        }
+
+        public char[] charArray(char[] a0, char[] a1, char[] a2) {
+            for (int i = 0; i < a0.length && i < a2.length; i++) {
+                a2[i] = a0[i];
+            }
+            for (int i = 0; i < a0.length && i < a1.length; i++) {
+                a1[i] = a0[i];
+            }
+            return a0;
+        }
+
+        public int[] intArray(int[] a0, int[] a1, int[] a2) {
+            for (int i = 0; i < a0.length && i < a2.length; i++) {
+                a2[i] = a0[i];
+            }
+            for (int i = 0; i < a0.length && i < a1.length; i++) {
+                a1[i] = a0[i];
+            }
+            return a0;
+        }
+
+        public long[] longArray(long[] a0, long[] a1, long[] a2) {
+            for (int i = 0; i < a0.length && i < a2.length; i++) {
+                a2[i] = a0[i];
+            }
+            for (int i = 0; i < a0.length && i < a1.length; i++) {
+                a1[i] = a0[i];
+            }
+            return a0;
+        }
+
+        public float[] floatArray(float[] a0, float[] a1, float[] a2) {
+            for (int i = 0; i < a0.length && i < a2.length; i++) {
+                a2[i] = a0[i];
+            }
+            for (int i = 0; i < a0.length && i < a1.length; i++) {
+                a1[i] = a0[i];
+            }
+            return a0;
+        }
+
+        public double[] doubleArray(double[] a0, double[] a1, double[] a2) {
+            for (int i = 0; i < a0.length && i < a2.length; i++) {
+                a2[i] = a0[i];
+            }
+            for (int i = 0; i < a0.length && i < a1.length; i++) {
+                a1[i] = a0[i];
+            }
+            return a0;
+        }
+
+        public String[] stringArray(String[] a0, String[] a1, String[] a2) {
+            for (int i = 0; i < a0.length && i < a2.length; i++) {
+                a2[i] = a0[i];
+            }
+            for (int i = 0; i < a0.length && i < a1.length; i++) {
+                a1[i] = a0[i];
+            }
+            return a0;
+        }
+
+        public TestParcelable[] parcelableArray(TestParcelable[] a0,
+                TestParcelable[] a1, TestParcelable[] a2) {
+            return null;
+        }
+        
+        public void voidSecurityException() {
+            throw new SecurityException("gotcha!");
+        }
+
+        public int intSecurityException() {
+            throw new SecurityException("gotcha!");
+        }
+    }
+
+    @SmallTest
+    public void testInt() throws Exception {
+        int result = mRemote.intMethod(42);
+        assertEquals(42, result);
+    }
+
+    @SmallTest
+    public void testParcelableIn() throws Exception {
+        TestParcelable arg = new TestParcelable(43, "hi");
+        TestParcelable result = mRemote.parcelableIn(arg);
+        assertNotSame(arg, result);
+
+        assertEquals(43, arg.mAnInt);
+        assertEquals(44, result.mAnInt);
+    }
+
+    @SmallTest
+    public void testParcelableOut() throws Exception {
+        TestParcelable arg = new TestParcelable(43, "hi");
+        TestParcelable result = mRemote.parcelableOut(arg);
+        assertNotSame(arg, result);
+        assertEquals(44, arg.mAnInt);
+    }
+
+    @SmallTest
+    public void testParcelableInOut() throws Exception {
+        TestParcelable arg = new TestParcelable(43, "hi");
+        TestParcelable result = mRemote.parcelableInOut(arg);
+        assertNotSame(arg, result);
+        assertEquals(44, arg.mAnInt);
+    }
+
+    @SmallTest
+    public void testListParcelableLonger() throws Exception {
+        List<TestParcelable> list = Lists.newArrayList();
+        list.add(new TestParcelable(33, "asdf"));
+        list.add(new TestParcelable(34, "jkl;"));
+
+        TestParcelable result = mRemote.listParcelableLonger(list, 1);
+
+//        System.out.println("result=" + result);
+//        for (TestParcelable p : list) {
+//            System.out.println("longer: " + p);
+//        }
+
+        assertEquals("jkl;", result.mAString);
+        assertEquals(34, result.mAnInt);
+
+        assertEquals(3, list.size());
+        assertTrue("out parameter 0: " + list.get(0), check(list.get(0), 33, "asdf"));
+        assertTrue("out parameter 1: " + list.get(1), check(list.get(1), 34, "jkl;"));
+        assertTrue("out parameter 2: " + list.get(2), check(list.get(2), 34, "jkl;"));
+
+        assertNotSame(list.get(1), list.get(2));
+    }
+
+    @SmallTest
+    public void testListParcelableShorter() throws Exception {
+        List<TestParcelable> list = Lists.newArrayList();
+        list.add(new TestParcelable(33, "asdf"));
+        list.add(new TestParcelable(34, "jkl;"));
+        list.add(new TestParcelable(35, "qwerty"));
+
+        int result = mRemote.listParcelableShorter(list, 2);
+
+//        System.out.println("result=" + result);
+//        for (TestParcelable p : list) {
+//            System.out.println("shorter: " + p);
+//        }
+
+        assertEquals(2, result);
+        assertEquals(2, list.size());
+        assertTrue("out parameter 0: " + list.get(0), check(list.get(0), 33, "asdf"));
+        assertTrue("out parameter 1: " + list.get(1), check(list.get(1), 34, "jkl;"));
+
+        assertNotSame(list.get(0), list.get(1));
+    }
+
+    @SmallTest
+    public void testArrays() throws Exception {
+        // boolean
+        boolean[] b0 = new boolean[]{true};
+        boolean[] b1 = new boolean[]{false, true};
+        boolean[] b2 = new boolean[]{true, false, true};
+        boolean[] br = mRemote.booleanArray(b0, b1, b2);
+
+        assertEquals(1, br.length);
+        assertTrue(br[0]);
+
+        assertTrue(b1[0]);
+        assertFalse(b1[1]);
+
+        assertTrue(b2[0]);
+        assertFalse(b2[1]);
+        assertTrue(b2[2]);
+
+        // char
+        char[] c0 = new char[]{'a'};
+        char[] c1 = new char[]{'b', 'c'};
+        char[] c2 = new char[]{'d', 'e', 'f'};
+        char[] cr = mRemote.charArray(c0, c1, c2);
+
+        assertEquals(1, cr.length);
+        assertEquals('a', cr[0]);
+
+        assertEquals('a', c1[0]);
+        assertEquals('\0', c1[1]);
+
+        assertEquals('a', c2[0]);
+        assertEquals('e', c2[1]);
+        assertEquals('f', c2[2]);
+
+        // int
+        int[] i0 = new int[]{34};
+        int[] i1 = new int[]{38, 39};
+        int[] i2 = new int[]{42, 43, 44};
+        int[] ir = mRemote.intArray(i0, i1, i2);
+
+        assertEquals(1, ir.length);
+        assertEquals(34, ir[0]);
+
+        assertEquals(34, i1[0]);
+        assertEquals(0, i1[1]);
+
+        assertEquals(34, i2[0]);
+        assertEquals(43, i2[1]);
+        assertEquals(44, i2[2]);
+
+        // long
+        long[] l0 = new long[]{50};
+        long[] l1 = new long[]{51, 52};
+        long[] l2 = new long[]{53, 54, 55};
+        long[] lr = mRemote.longArray(l0, l1, l2);
+
+        assertEquals(1, lr.length);
+        assertEquals(50, lr[0]);
+
+        assertEquals(50, l1[0]);
+        assertEquals(0, l1[1]);
+
+        assertEquals(50, l2[0]);
+        assertEquals(54, l2[1]);
+        assertEquals(55, l2[2]);
+
+        // float
+        float[] f0 = new float[]{90.1f};
+        float[] f1 = new float[]{90.2f, 90.3f};
+        float[] f2 = new float[]{90.4f, 90.5f, 90.6f};
+        float[] fr = mRemote.floatArray(f0, f1, f2);
+
+        assertEquals(1, fr.length);
+        assertEquals(90.1f, fr[0]);
+
+        assertEquals(90.1f, f1[0]);
+        assertEquals(0f, f1[1], 0.0f);
+
+        assertEquals(90.1f, f2[0]);
+        assertEquals(90.5f, f2[1]);
+        assertEquals(90.6f, f2[2]);
+
+        // double
+        double[] d0 = new double[]{100.1};
+        double[] d1 = new double[]{100.2, 100.3};
+        double[] d2 = new double[]{100.4, 100.5, 100.6};
+        double[] dr = mRemote.doubleArray(d0, d1, d2);
+
+        assertEquals(1, dr.length);
+        assertEquals(100.1, dr[0]);
+
+        assertEquals(100.1, d1[0]);
+        assertEquals(0, d1[1], 0.0);
+
+        assertEquals(100.1, d2[0]);
+        assertEquals(100.5, d2[1]);
+        assertEquals(100.6, d2[2]);
+
+        // String
+        String[] s0 = new String[]{"s0[0]"};
+        String[] s1 = new String[]{"s1[0]", "s1[1]"};
+        String[] s2 = new String[]{"s2[0]", "s2[1]", "s2[2]"};
+        String[] sr = mRemote.stringArray(s0, s1, s2);
+
+        assertEquals(1, sr.length);
+        assertEquals("s0[0]", sr[0]);
+
+        assertEquals("s0[0]", s1[0]);
+        assertNull(s1[1]);
+
+        assertEquals("s0[0]", s2[0]);
+        assertEquals("s2[1]", s2[1]);
+        assertEquals("s2[2]", s2[2]);
+    }
+    
+    @SmallTest
+    public void testVoidSecurityException() throws Exception {
+        boolean good = false;
+        try {
+            mRemote.voidSecurityException();
+        } catch (SecurityException e) {
+            good = true;
+        }
+        assertEquals(good, true);
+    }
+    
+    @SmallTest
+    public void testIntSecurityException() throws Exception {
+        boolean good = false;
+        try {
+            mRemote.intSecurityException();
+        } catch (SecurityException e) {
+            good = true;
+        }
+        assertEquals(good, true);
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java
new file mode 100644
index 0000000..0df1653
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.os;
+
+import android.os.Broadcaster;
+import android.os.Handler;
+import android.os.Message;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+public class BroadcasterTest extends TestCase {
+    private static final int MESSAGE_A = 23234;
+    private static final int MESSAGE_B = 3;
+    private static final int MESSAGE_C = 14;
+    private static final int MESSAGE_D = 95;
+
+    @MediumTest
+    public void test1() throws Exception {
+        /*
+        * One handler requestes one message, with a translation
+        */
+        HandlerTester tester = new HandlerTester() {
+            Handler h;
+
+            public void go() {
+                Broadcaster b = new Broadcaster();
+                h = new H();
+
+                b.request(MESSAGE_A, h, MESSAGE_B);
+
+                Message msg = new Message();
+                msg.what = MESSAGE_A;
+
+                b.broadcast(msg);
+            }
+
+            public void handleMessage(Message msg) {
+                if (msg.what == MESSAGE_B) {
+                    success();
+                } else {
+                    failure();
+                }
+            }
+        };
+        tester.doTest(1000);
+    }
+
+    private static class Tests2and3 extends HandlerTester {
+        Tests2and3(int n) {
+            N = n;
+        }
+
+        int N;
+        Handler mHandlers[];
+        boolean mSuccess[];
+
+        public void go() {
+            Broadcaster b = new Broadcaster();
+            mHandlers = new Handler[N];
+            mSuccess = new boolean[N];
+            for (int i = 0; i < N; i++) {
+                mHandlers[i] = new H();
+                mSuccess[i] = false;
+                b.request(MESSAGE_A, mHandlers[i], MESSAGE_B + i);
+            }
+
+            Message msg = new Message();
+            msg.what = MESSAGE_A;
+
+            b.broadcast(msg);
+        }
+
+        public void handleMessage(Message msg) {
+            int index = msg.what - MESSAGE_B;
+            if (index < 0 || index >= N) {
+                failure();
+            } else {
+                if (msg.getTarget() == mHandlers[index]) {
+                    mSuccess[index] = true;
+                }
+            }
+            boolean winner = true;
+            for (int i = 0; i < N; i++) {
+                if (!mSuccess[i]) {
+                    winner = false;
+                }
+            }
+            if (winner) {
+                success();
+            }
+        }
+    }
+
+    @MediumTest
+    public void test2() throws Exception {
+        /*
+        * 2 handlers request the same message, with different translations
+        */
+        HandlerTester tester = new Tests2and3(2);
+        tester.doTest(1000);
+    }
+
+    @MediumTest
+    public void test3() throws Exception {
+        /*
+        * 1000 handlers request the same message, with different translations
+        */
+        HandlerTester tester = new Tests2and3(10);
+        tester.doTest(1000);
+    }
+
+    @MediumTest
+    public void test4() throws Exception {
+        /*
+        * Two handlers request different messages, with translations, sending
+        * only one.  The other one should never get sent.
+        */
+        HandlerTester tester = new HandlerTester() {
+            Handler h1;
+            Handler h2;
+
+            public void go() {
+                Broadcaster b = new Broadcaster();
+                h1 = new H();
+                h2 = new H();
+
+                b.request(MESSAGE_A, h1, MESSAGE_C);
+                b.request(MESSAGE_B, h2, MESSAGE_D);
+
+                Message msg = new Message();
+                msg.what = MESSAGE_A;
+
+                b.broadcast(msg);
+            }
+
+            public void handleMessage(Message msg) {
+                if (msg.what == MESSAGE_C && msg.getTarget() == h1) {
+                    success();
+                } else {
+                    failure();
+                }
+            }
+        };
+        tester.doTest(1000);
+    }
+
+    @MediumTest
+    public void test5() throws Exception {
+        /*
+        * Two handlers request different messages, with translations, sending
+        * only one.  The other one should never get sent.
+        */
+        HandlerTester tester = new HandlerTester() {
+            Handler h1;
+            Handler h2;
+
+            public void go() {
+                Broadcaster b = new Broadcaster();
+                h1 = new H();
+                h2 = new H();
+
+                b.request(MESSAGE_A, h1, MESSAGE_C);
+                b.request(MESSAGE_B, h2, MESSAGE_D);
+
+                Message msg = new Message();
+                msg.what = MESSAGE_B;
+
+                b.broadcast(msg);
+            }
+
+            public void handleMessage(Message msg) {
+                if (msg.what == MESSAGE_D && msg.getTarget() == h2) {
+                    success();
+                } else {
+                    failure();
+                }
+            }
+        };
+        tester.doTest(1000);
+    }
+
+    @MediumTest
+    public void test6() throws Exception {
+        /*
+        * Two handlers request same message. Cancel the request for the
+        * 2nd handler, make sure the first still works.
+        */
+        HandlerTester tester = new HandlerTester() {
+            Handler h1;
+            Handler h2;
+
+            public void go() {
+                Broadcaster b = new Broadcaster();
+                h1 = new H();
+                h2 = new H();
+
+                b.request(MESSAGE_A, h1, MESSAGE_C);
+                b.request(MESSAGE_A, h2, MESSAGE_D);
+                b.cancelRequest(MESSAGE_A, h2, MESSAGE_D);
+
+                Message msg = new Message();
+                msg.what = MESSAGE_A;
+
+                b.broadcast(msg);
+            }
+
+            public void handleMessage(Message msg) {
+                if (msg.what == MESSAGE_C && msg.getTarget() == h1) {
+                    success();
+                } else {
+                    failure();
+                }
+            }
+        };
+        tester.doTest(1000);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java
new file mode 100644
index 0000000..a504cd3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import android.os.FileObserver;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class FileObserverTest extends AndroidTestCase {
+    private Observer mObserver;
+    private File mTestFile;
+    
+    private static class Observer extends FileObserver {
+        public List<Map> events = Lists.newArrayList();
+        public int totalEvents = 0;
+
+        public Observer(String path) {
+            super(path);
+        }
+
+        public void onEvent(int event, String path) {
+            synchronized (this) {
+                totalEvents++;
+                Map<String, Object> map = Maps.newHashMap();
+
+                map.put("event", event);
+                map.put("path", path);
+
+                events.add(map);
+
+                this.notifyAll();
+            }
+        }
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        mTestFile = File.createTempFile(".file_observer_test", ".txt"); 
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mTestFile != null && mTestFile.exists()) {
+            mTestFile.delete();
+        }
+    }
+    
+    @LargeTest
+    public void testRun() throws Exception {
+        // make file changes and wait for them
+        assertTrue(mTestFile.exists());
+        assertNotNull(mTestFile.getParent());
+        
+        mObserver = new Observer(mTestFile.getParent());
+        mObserver.startWatching();
+
+        FileOutputStream out = new FileOutputStream(mTestFile);
+        try {
+            out.write(0x20);
+            waitForEvent(); // open
+            waitForEvent(); // modify
+
+            mTestFile.delete();
+            waitForEvent(); // delete
+
+            mObserver.stopWatching();
+            
+            // Ensure that we have seen at least 3 events.
+            assertTrue(mObserver.totalEvents > 3);
+        } finally {
+            out.close();
+        }
+    }
+
+    private void waitForEvent() {
+        synchronized (mObserver) {
+            boolean done = false;
+            while (!done) {
+                try {
+                    mObserver.wait(2000);
+                    done = true;
+                } catch (InterruptedException e) {
+                }
+            }
+
+            Iterator<Map> it = mObserver.events.iterator();
+
+            while (it.hasNext()) {
+                Map map = it.next();
+                Log.i("FileObserverTest", "event: " + map.get("event").toString() + " path: " + map.get("path"));
+            }
+
+            mObserver.events.clear();
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java
new file mode 100644
index 0000000..f2c9293
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.os;
+
+import android.content.Context;
+import android.os.FileUtils;
+import android.os.FileUtils.FileStatus;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import junit.framework.Assert;
+
+public class FileUtilsTest extends AndroidTestCase {
+    private static final String TEST_DATA =
+            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+    private File mTestFile;
+    private File mCopyFile;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        File testDir = getContext().getDir("testing", Context.MODE_PRIVATE);
+        mTestFile = new File(testDir, "test.file");
+        mCopyFile = new File(testDir, "copy.file");
+        FileWriter writer = new FileWriter(mTestFile);
+        try {
+            writer.write(TEST_DATA, 0, TEST_DATA.length());
+        } finally {
+            writer.close();
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mTestFile.exists()) mTestFile.delete();
+        if (mCopyFile.exists()) mCopyFile.delete();
+    }
+
+    @LargeTest
+    public void testGetFileStatus() {
+        final byte[] MAGIC = { 0xB, 0xE, 0x0, 0x5 };
+
+        try {
+            // truncate test file and write MAGIC (4 bytes) to it.
+            FileOutputStream os = new FileOutputStream(mTestFile, false);
+            os.write(MAGIC, 0, 4);
+            os.flush();
+            os.close();
+        } catch (FileNotFoundException e) {
+            Assert.fail("File was removed durning test" + e);
+        } catch (IOException e) {
+            Assert.fail("Unexpected IOException: " + e);
+        }
+        
+        Assert.assertTrue(mTestFile.exists());
+        Assert.assertTrue(FileUtils.getFileStatus(mTestFile.getPath(), null));
+        
+        FileStatus status1 = new FileStatus();
+        FileUtils.getFileStatus(mTestFile.getPath(), status1);
+        
+        Assert.assertEquals(4, status1.size);
+        
+        // Sleep for at least one second so that the modification time will be different.
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+        }
+
+        try {
+            // append so we don't change the creation time.
+            FileOutputStream os = new FileOutputStream(mTestFile, true);
+            os.write(MAGIC, 0, 4);
+            os.flush();
+            os.close();
+        } catch (FileNotFoundException e) {
+            Assert.fail("File was removed durning test" + e);
+        } catch (IOException e) {
+            Assert.fail("Unexpected IOException: " + e);
+        }
+        
+        FileStatus status2 = new FileStatus();
+        FileUtils.getFileStatus(mTestFile.getPath(), status2);
+        
+        Assert.assertEquals(8, status2.size);
+        Assert.assertTrue(status2.mtime > status1.mtime);
+        
+        mTestFile.delete();
+        
+        Assert.assertFalse(mTestFile.exists());
+        Assert.assertFalse(FileUtils.getFileStatus(mTestFile.getPath(), null));
+    }
+
+    // TODO: test setPermissions(), getPermissions()
+
+    @MediumTest
+    public void testCopyFile() throws Exception {
+        assertFalse(mCopyFile.exists());
+        FileUtils.copyFile(mTestFile, mCopyFile);
+        assertTrue(mCopyFile.exists());
+        assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null));
+    }
+
+    @MediumTest
+    public void testCopyToFile() throws Exception {
+        final String s = "Foo Bar";
+        assertFalse(mCopyFile.exists());
+        FileUtils.copyToFile(new ByteArrayInputStream(s.getBytes()), mCopyFile);        assertTrue(mCopyFile.exists());
+        assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null));
+    }
+
+    @MediumTest
+    public void testIsFilenameSafe() throws Exception {
+        assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
+        assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
+        assertFalse(FileUtils.isFilenameSafe(new File("foo*bar")));
+        assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar")));
+    }
+
+    @MediumTest
+    public void testReadTextFile() throws Exception {
+        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 0, null));
+
+        assertEquals("ABCDE", FileUtils.readTextFile(mTestFile, 5, null));
+        assertEquals("ABCDE<>", FileUtils.readTextFile(mTestFile, 5, "<>"));
+        assertEquals(TEST_DATA.substring(0, 51) + "<>",
+                FileUtils.readTextFile(mTestFile, 51, "<>"));
+        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 52, "<>"));
+        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 100, "<>"));
+
+        assertEquals("vwxyz", FileUtils.readTextFile(mTestFile, -5, null));
+        assertEquals("<>vwxyz", FileUtils.readTextFile(mTestFile, -5, "<>"));
+        assertEquals("<>" + TEST_DATA.substring(1, 52),
+                FileUtils.readTextFile(mTestFile, -51, "<>"));
+        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -52, "<>"));
+        assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>"));
+    }
+
+    @MediumTest
+    public void testReadTextFileWithZeroLengthFile() throws Exception {
+        new FileOutputStream(mTestFile).close();  // Zero out the file
+        assertEquals("", FileUtils.readTextFile(mTestFile, 0, null));
+        assertEquals("", FileUtils.readTextFile(mTestFile, 1, "<>"));
+        assertEquals("", FileUtils.readTextFile(mTestFile, 10, "<>"));
+        assertEquals("", FileUtils.readTextFile(mTestFile, -1, "<>"));
+        assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>"));
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerStateMachineTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerStateMachineTest.java
new file mode 100644
index 0000000..29045a3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerStateMachineTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import junit.framework.TestCase;
+import java.util.Vector;
+
+import android.os.Handler;
+import android.os.HandlerState;
+import android.os.HandlerStateMachine;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
+import android.os.Message;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import android.util.Log;
+
+public class HandlerStateMachineTest extends TestCase {
+    private static final int TEST_WHAT_1 = 1;
+    private static final int TEST_WHAT_2 = 2;
+
+    private static final boolean DBG = false;
+    private static final String TAG = "HandlerStateMachineTest";
+
+    private boolean mDidEnter = false;
+    private boolean mDidExit = false;
+    private Vector<Integer> mGotMessagesWhat = new Vector<Integer>();
+
+    /**
+     * This test statemachine has two states, it receives
+     * two messages in state mS1 deferring them until what == TEST_WHAT_2
+     * and then transitions to state mS2. State mS2 should then receive
+     * both of the deferred messages first TEST_WHAT_1 and then TEST_WHAT_2.
+     * When TEST_WHAT_2 is received it invokes notifyAll so the test can
+     * conclude.
+     */
+    class StateMachine1 extends HandlerStateMachine {
+        StateMachine1(String name) {
+            super(name);
+            mThisSm = this;
+            setDbg(DBG);
+            setInitialState(mS1);
+        }
+
+        class S1 extends HandlerState {
+            @Override public void enter(Message message) {
+                mDidEnter = true;
+            }
+
+            @Override public void processMessage(Message message) {
+                deferMessage(message);
+                if (message.what == TEST_WHAT_2) {
+                    transitionTo(mS2);
+                }
+            }
+
+            @Override public void exit(Message message) {
+                mDidExit = true;
+            }
+        }
+
+        class S2 extends HandlerState {
+            @Override public void processMessage(Message message) {
+                mGotMessagesWhat.add(message.what);
+                if (message.what == TEST_WHAT_2) {
+                    synchronized (mThisSm) {
+                        mThisSm.notifyAll();
+                    }
+                }
+            }
+        }
+
+        private StateMachine1 mThisSm;
+        private S1 mS1 = new S1();
+        private S2 mS2 = new S2();
+    }
+
+    @SmallTest
+    public void testStateMachine1() throws Exception {
+        StateMachine1 sm1 = new StateMachine1("sm1");
+        if (sm1.isDbg()) Log.d(TAG, "testStateMachine1 E");
+
+        synchronized (sm1) {
+            // Send two messages
+            sm1.sendMessage(sm1.obtainMessage(TEST_WHAT_1));
+            sm1.sendMessage(sm1.obtainMessage(TEST_WHAT_2));
+
+            try {
+                // wait for the messages to be handled
+                sm1.wait();
+            } catch (InterruptedException e) {
+                Log.e(TAG, "testStateMachine1: exception while waiting " + e.getMessage());
+            }
+        }
+
+        assertTrue(mDidEnter);
+        assertTrue(mDidExit);
+        assertTrue(mGotMessagesWhat.size() == 2);
+        assertTrue(mGotMessagesWhat.get(0) == TEST_WHAT_1);
+        assertTrue(mGotMessagesWhat.get(1) == TEST_WHAT_2);
+        if (sm1.isDbg()) Log.d(TAG, "testStateMachine1 X");
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java
new file mode 100644
index 0000000..303245f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.os;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+public abstract class HandlerTester extends Thread {
+    public abstract void go();
+    public abstract void handleMessage(Message msg);
+
+    public HandlerTester() {
+    }
+
+    public void doTest(long timeout) {
+        start();
+
+        synchronized (this) {
+            try {
+                wait(timeout);
+                quit();
+            }
+            catch (InterruptedException e) {
+            }
+        }
+
+        if (!mDone) {
+            throw new RuntimeException("test timed out");
+        }
+        if (!mSuccess) {
+            throw new RuntimeException("test failed");
+        }
+    }
+
+    public void success() {
+        mDone = true;
+        mSuccess = true;
+    }
+
+    public void failure() {
+        mDone = true;
+        mSuccess = false;
+    }
+
+    public void run() {
+        Looper.prepare();
+        mLooper = Looper.myLooper();
+        go();
+        Looper.loop();
+    }
+
+    protected class H extends Handler {
+        public void handleMessage(Message msg) {
+            synchronized (HandlerTester.this) {
+                // Call into them with our monitor locked, so they don't have
+                // to deal with other races.
+                HandlerTester.this.handleMessage(msg);
+                if (mDone) {
+                    HandlerTester.this.notify();
+                    quit();
+                }
+            }
+        }
+    }
+
+    private void quit() {
+        mLooper.quit();
+    }
+
+    private boolean mDone = false;
+    private boolean mSuccess = false;
+    private Looper mLooper;
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
new file mode 100644
index 0000000..c62f94f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import junit.framework.TestCase;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.Process;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class HandlerThreadTest extends TestCase {
+    private static final int TEST_WHAT = 1;
+
+    private boolean mGotMessage = false;
+    private int mGotMessageWhat = -1;
+    private volatile boolean mDidSetup = false;
+    private volatile int mLooperTid = -1;
+    
+    @MediumTest
+    public void testHandlerThread() throws Exception {
+        HandlerThread th1 =  new HandlerThread("HandlerThreadTest") {
+            protected void onLooperPrepared() {
+                mDidSetup = true;
+                mLooperTid = Process.myTid();
+            }
+        };
+        
+        assertFalse(th1.isAlive());
+        assertNull(th1.getLooper());
+        
+        th1.start();
+        
+        assertTrue(th1.isAlive());
+        assertNotNull(th1.getLooper());
+       
+        /* 
+         * Since getLooper() will block until the HandlerThread is setup, we are guaranteed
+         * that mDidSetup and mLooperTid will have been initalized. If they have not, then 
+         * this test should fail
+         */
+        // Make sure that the onLooperPrepared() was called on a different thread.
+        assertNotSame(Process.myTid(), mLooperTid);
+        assertTrue(mDidSetup);
+        
+        final Handler h1 = new Handler(th1.getLooper()) {
+            public void handleMessage(Message msg) {
+                assertEquals(TEST_WHAT, msg.what);
+                // Ensure that we are running on the same thread in which the looper was setup on.
+                assertEquals(mLooperTid, Process.myTid());
+                
+                mGotMessageWhat = msg.what;
+                mGotMessage = true;
+                synchronized(this) {
+                    notifyAll();
+                }
+            }
+        };
+        
+        Message msg = h1.obtainMessage(TEST_WHAT);
+        
+        synchronized (h1) {
+            // wait until we have the lock before sending the message.
+            h1.sendMessage(msg);
+            try {
+                // wait for the message to be handled
+                h1.wait();
+            } catch (InterruptedException e) {
+            }
+        }
+        
+        assertTrue(mGotMessage);
+        assertEquals(TEST_WHAT, mGotMessageWhat);
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl b/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl
new file mode 100644
index 0000000..94c39ff
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl
@@ -0,0 +1,47 @@
+/* //device/apps/AndroidTests/src/com.android.unit_tests/IAidlTest.aidl
+**
+** Copyright 2007, 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.unit_tests.os;
+
+import com.android.unit_tests.os.AidlTest;
+
+interface IAidlTest {
+    int intMethod(int a);
+
+    AidlTest.TestParcelable parcelableIn(in AidlTest.TestParcelable p);
+    AidlTest.TestParcelable parcelableOut(out AidlTest.TestParcelable p);
+    AidlTest.TestParcelable parcelableInOut(inout AidlTest.TestParcelable p);
+
+    AidlTest.TestParcelable listParcelableLonger(
+                    inout List<AidlTest.TestParcelable> list, int index);
+    int listParcelableShorter(
+                    inout List<AidlTest.TestParcelable> list, int index);
+
+    boolean[] booleanArray(in boolean[] a0, out boolean[] a1, inout boolean[] a2);
+    char[] charArray(in char[] a0, out char[] a1, inout char[] a2);
+    int[] intArray(in int[] a0, out int[] a1, inout int[] a2);
+    long[] longArray(in long[] a0, out long[] a1, inout long[] a2);
+    float[] floatArray(in float[] a0, out float[] a1, inout float[] a2);
+    double[] doubleArray(in double[] a0, out double[] a1, inout double[] a2);
+    String[] stringArray(in String[] a0, out String[] a1, inout String[] a2);
+    AidlTest.TestParcelable[] parcelableArray(in AidlTest.TestParcelable[] a0,
+                                          out AidlTest.TestParcelable[] a1,
+                                          inout AidlTest.TestParcelable[] a2);
+                                          
+    void voidSecurityException();
+    int intSecurityException();
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java
new file mode 100644
index 0000000..fc3b007
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.os;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue.IdleHandler;
+import android.test.suitebuilder.annotation.MediumTest;
+import junit.framework.TestCase;
+
+public class IdleHandlerTest extends TestCase {
+
+    private static class BaseTestHandler extends TestHandlerThread {
+        Handler mHandler;
+
+        public BaseTestHandler() {
+        }
+
+        public void go() {
+            mHandler = new Handler() {
+                public void handleMessage(Message msg) {
+                    BaseTestHandler.this.handleMessage(msg);
+                }
+            };
+        }
+
+        public void addIdleHandler() {
+            Looper.myQueue().addIdleHandler(new IdleHandler() {
+                public boolean queueIdle() {
+                    return BaseTestHandler.this.queueIdle();
+                }
+            });
+        }
+
+        public void handleMessage(Message msg) {
+        }
+
+        public boolean queueIdle() {
+            return false;
+        }
+    }
+
+    @MediumTest
+    public void testOneShotFirst() throws Exception {
+        TestHandlerThread tester = new BaseTestHandler() {
+            int mCount;
+
+            public void go() {
+                super.go();
+                mCount = 0;
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 100);
+                addIdleHandler();
+            }
+
+            public void handleMessage(Message msg) {
+                if (msg.what == 0) {
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100);
+                } else if (msg.what == 1) {
+                    if (mCount == 1) {
+                        success();
+                    } else {
+                        failure(new RuntimeException(
+                                "Idle handler called " + mCount + " times"));
+                    }
+                }
+            }
+
+            public boolean queueIdle() {
+                mCount++;
+                return false;
+            }
+        };
+
+        tester.doTest(1000);
+    }
+
+    @MediumTest
+    public void testOneShotLater() throws Exception {
+        TestHandlerThread tester = new BaseTestHandler() {
+            int mCount;
+
+            public void go() {
+                super.go();
+                mCount = 0;
+                mHandler.sendMessage(mHandler.obtainMessage(0));
+            }
+
+            public void handleMessage(Message msg) {
+                if (msg.what == 0) {
+                    addIdleHandler();
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100);
+                } else if (msg.what == 1) {
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(2), 100);
+                } else if (msg.what == 2) {
+                    if (mCount == 1) {
+                        success();
+                    } else {
+                        failure(new RuntimeException(
+                                "Idle handler called " + mCount + " times"));
+                    }
+                }
+            }
+
+            public boolean queueIdle() {
+                mCount++;
+                return false;
+            }
+        };
+
+        tester.doTest(1000);
+    }
+
+
+    @MediumTest
+    public void testRepeatedFirst() throws Exception {
+        TestHandlerThread tester = new BaseTestHandler() {
+            int mCount;
+
+            public void go() {
+                super.go();
+                mCount = 0;
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 100);
+                addIdleHandler();
+            }
+
+            public void handleMessage(Message msg) {
+                if (msg.what == 0) {
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100);
+                } else if (msg.what == 1) {
+                    if (mCount == 2) {
+                        success();
+                    } else {
+                        failure(new RuntimeException(
+                                "Idle handler called " + mCount + " times"));
+                    }
+                }
+            }
+
+            public boolean queueIdle() {
+                mCount++;
+                return true;
+            }
+        };
+
+        tester.doTest(1000);
+    }
+
+    @MediumTest
+    public void testRepeatedLater() throws Exception {
+        TestHandlerThread tester = new BaseTestHandler() {
+            int mCount;
+
+            public void go() {
+                super.go();
+                mCount = 0;
+                mHandler.sendMessage(mHandler.obtainMessage(0));
+            }
+
+            public void handleMessage(Message msg) {
+                if (msg.what == 0) {
+                    addIdleHandler();
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100);
+                } else if (msg.what == 1) {
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(2), 100);
+                } else if (msg.what == 2) {
+                    if (mCount == 2) {
+                        success();
+                    } else {
+                        failure(new RuntimeException(
+                                "Idle handler called " + mCount + " times"));
+                    }
+                }
+            }
+
+            public boolean queueIdle() {
+                mCount++;
+                return true;
+            }
+        };
+
+        tester.doTest(1000);
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java
new file mode 100644
index 0000000..508afcf
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.os;
+
+import android.os.MemoryFile;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class MemoryFileTest extends TestCase {
+
+    private void compareBuffers(byte[] buffer1, byte[] buffer2, int length) throws Exception {
+        for (int i = 0; i < length; i++) {
+            if (buffer1[i] != buffer2[i]) {
+                throw new Exception("readBytes did not read back what writeBytes wrote");
+            }
+        }
+    }
+
+    /**
+     * Keep allocating new files till the system purges them.
+     */
+    @MediumTest
+    public void testPurge() throws Exception {
+        List<MemoryFile> files = new ArrayList<MemoryFile>();
+        while (true) {
+            MemoryFile newFile = new MemoryFile("MemoryFileTest", 1000000);
+            newFile.allowPurging(true);
+            newFile.writeBytes(testString, 0, 0, testString.length);
+            files.add(newFile);
+            for (MemoryFile file : files) {
+                try {
+                    file.readBytes(testString, 0, 0, testString.length);
+                } catch (IOException e) {
+                    // Expected
+                    for (MemoryFile fileToClose : files) {
+                        fileToClose.close();
+                    }
+                    return;
+                }
+            }
+        }
+    }
+
+    @SmallTest
+    public void testRun() throws Exception {
+        MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
+
+        byte[] buffer = new byte[testString.length];
+
+        // check low level accessors
+        file.writeBytes(testString, 0, 2000, testString.length);
+        file.readBytes(buffer, 2000, 0, testString.length);
+        compareBuffers(testString, buffer, testString.length);
+
+        // check streams
+        buffer = new byte[testString.length];
+
+        OutputStream os = file.getOutputStream();
+        os.write(testString);
+
+        InputStream is = file.getInputStream();
+        is.mark(testString.length);
+        is.read(buffer);
+        compareBuffers(testString, buffer, testString.length);
+
+        // test mark/reset
+        buffer = new byte[testString.length];
+        is.reset();
+        is.read(buffer);
+        compareBuffers(testString, buffer, testString.length);
+
+        file.close();
+    }
+
+    private static final byte[] testString = new byte[] {
+        3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4,
+        0, 6, 2, 8, 6, 2, 0, 8, 9, 9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1, 1, 7, 0, 6, 7, 9, 8, 2, 1, 4, 8, 0, 8, 6, 5, 1, 3, 2, 8, 2, 3, 0, 6, 6, 4, 7, 0, 9, 3, 8, 4, 4, 6, 0, 9, 5, 5, 0, 5, 8, 2, 2, 3, 1, 7, 2,
+        5, 3, 5, 9, 4, 0, 8, 1, 2, 8, 4, 8, 1, 1, 1, 7, 4, 5, 0, 2, 8, 4, 1, 0, 2, 7, 0, 1, 9, 3, 8, 5, 2, 1, 1, 0, 5, 5, 5, 9, 6, 4, 4, 6, 2, 2, 9, 4, 8, 9, 5, 4, 9, 3, 0, 3, 8, 1, 9, 6, 4, 4, 2, 8, 8, 1, 0, 9, 7, 5,
+        6, 6, 5, 9, 3, 3, 4, 4, 6, 1, 2, 8, 4, 7, 5, 6, 4, 8, 2, 3, 3, 7, 8, 6, 7, 8, 3, 1, 6, 5, 2, 7, 1, 2, 0, 1, 9, 0, 9, 1, 4, 5, 6, 4, 8, 5, 6, 6, 9, 2, 3, 4, 6, 0, 3, 4, 8, 6, 1, 0, 4, 5, 4, 3, 2, 6, 6, 4, 8, 2,
+        1, 3, 3, 9, 3, 6, 0, 7, 2, 6, 0, 2, 4, 9, 1, 4, 1, 2, 7, 3, 7, 2, 4, 5, 8, 7, 0, 0, 6, 6, 0, 6, 3, 1, 5, 5, 8, 8, 1, 7, 4, 8, 8, 1, 5, 2, 0, 9, 2, 0, 9, 6, 2, 8, 2, 9, 2, 5, 4, 0, 9, 1, 7, 1, 5, 3, 6, 4, 3, 6,
+        7, 8, 9, 2, 5, 9, 0, 3, 6, 0, 0, 1, 1, 3, 3, 0, 5, 3, 0, 5, 4, 8, 8, 2, 0, 4, 6, 6, 5, 2, 1, 3, 8, 4, 1, 4, 6, 9, 5, 1, 9, 4, 1, 5, 1, 1, 6, 0, 9, 4, 3, 3, 0, 5, 7, 2, 7, 0, 3, 6, 5, 7, 5, 9, 5, 9, 1, 9, 5, 3,
+        0, 9, 2, 1, 8, 6, 1, 1, 7, 3, 8, 1, 9, 3, 2, 6, 1, 1, 7, 9, 3, 1, 0, 5, 1, 1, 8, 5, 4, 8, 0, 7, 4, 4, 6, 2, 3, 7, 9, 9, 6, 2, 7, 4, 9, 5, 6, 7, 3, 5, 1, 8, 8, 5, 7, 5, 2, 7, 2, 4, 8, 9, 1, 2, 2, 7, 9, 3, 8, 1,
+        8, 3, 0, 1, 1, 9, 4, 9, 1, 2, 9, 8, 3, 3, 6, 7, 3, 3, 6, 2, 4, 4, 0, 6, 5, 6, 6, 4, 3, 0, 8, 6, 0, 2, 1, 3, 9, 4, 9, 4, 6, 3, 9, 5, 2, 2, 4, 7, 3, 7, 1, 9, 0, 7, 0, 2, 1, 7, 9, 8, 6, 0, 9, 4, 3, 7, 0, 2, 7, 7,
+        0, 5, 3, 9, 2, 1, 7, 1, 7, 6, 2, 9, 3, 1, 7, 6, 7, 5, 2, 3, 8, 4, 6, 7, 4, 8, 1, 8, 4, 6, 7, 6, 6, 9, 4, 0, 5, 1, 3, 2, 0, 0, 0, 5, 6, 8, 1, 2, 7, 1, 4, 5, 2, 6, 3, 5, 6, 0, 8, 2, 7, 7, 8, 5, 7, 7, 1, 3, 4, 2,
+        7, 5, 7, 7, 8, 9, 6, 0, 9, 1, 7, 3, 6, 3, 7, 1, 7, 8, 7, 2, 1, 4, 6, 8, 4, 4, 0, 9, 0, 1, 2, 2, 4, 9, 5, 3, 4, 3, 0, 1, 4, 6, 5, 4, 9, 5, 8, 5, 3, 7, 1, 0, 5, 0, 7, 9, 2, 2, 7, 9, 6, 8, 9, 2, 5, 8, 9, 2, 3, 5,
+        4, 2, 0, 1, 9, 9, 5, 6, 1, 1, 2, 1, 2, 9, 0, 2, 1, 9, 6, 0, 8, 6, 4, 0, 3, 4, 4, 1, 8, 1, 5, 9, 8, 1, 3, 6, 2, 9, 7, 7, 4, 7, 7, 1, 3, 0, 9, 9, 6, 0, 5, 1, 8, 7, 0, 7, 2, 1, 1, 3, 4, 9, 9, 9, 9, 9, 9, 8, 3, 7,
+        2, 9, 7, 8, 0, 4, 9, 9, 5, 1, 0, 5, 9, 7, 3, 1, 7, 3, 2, 8, 1, 6, 0, 9, 6, 3, 1, 8, 5, 9, 5, 0, 2, 4, 4, 5, 9, 4, 5, 5, 3, 4, 6, 9, 0, 8, 3, 0, 2, 6, 4, 2, 5, 2, 2, 3, 0, 8, 2, 5, 3, 3, 4, 4, 6, 8, 5, 0, 3, 5,
+        2, 6, 1, 9, 3, 1, 1, 8, 8, 1, 7, 1, 0, 1, 0, 0, 0, 3, 1, 3, 7, 8, 3, 8, 7, 5, 2, 8, 8, 6, 5, 8, 7, 5, 3, 3, 2, 0, 8, 3, 8, 1, 4, 2, 0, 6, 1, 7, 1, 7, 7, 6, 6, 9, 1, 4, 7, 3, 0, 3, 5, 9, 8, 2, 5, 3, 4, 9, 0, 4,
+        2, 8, 7, 5, 5, 4, 6, 8, 7, 3, 1, 1, 5, 9, 5, 6, 2, 8, 6, 3, 8, 8, 2, 3, 5, 3, 7, 8, 7, 5, 9, 3, 7, 5, 1, 9, 5, 7, 7, 8, 1, 8, 5, 7, 7, 8, 0, 5, 3, 2, 1, 7, 1, 2, 2, 6, 8, 0, 6, 6, 1, 3, 0, 0, 1, 9, 2, 7, 8, 7,
+        6, 6, 1, 1, 1, 9, 5, 9, 0, 9, 2, 1, 6, 4, 2, 0, 1, 9, 8, 9, 3, 8, 0, 9, 5, 2, 5, 7, 2, 0, 1, 0, 6, 5, 4, 8, 5, 8, 6, 3, 2, 7, 8, 8, 6, 5, 9, 3, 6, 1, 5, 3, 3, 8, 1, 8, 2, 7, 9, 6, 8, 2, 3, 0, 3, 0, 1, 9, 5, 2,
+        0, 3, 5, 3, 0, 1, 8, 5, 2, 9, 6, 8, 9, 9, 5, 7, 7, 3, 6, 2, 2, 5, 9, 9, 4, 1, 3, 8, 9, 1, 2, 4, 9, 7, 2, 1, 7, 7, 5, 2, 8, 3, 4, 7, 9, 1, 3, 1, 5, 1, 5, 5, 7, 4, 8, 5, 7, 2, 4, 2, 4, 5, 4, 1, 5, 0, 6, 9, 5, 9,
+        5, 0, 8, 2, 9, 5, 3, 3, 1, 1, 6, 8, 6, 1, 7, 2, 7, 8, 5, 5, 8, 8, 9, 0, 7, 5, 0, 9, 8, 3, 8, 1, 7, 5, 4, 6, 3, 7, 4, 6, 4, 9, 3, 9, 3, 1, 9, 2, 5, 5, 0, 6, 0, 4, 0, 0, 9, 2, 7, 7, 0, 1, 6, 7, 1, 1, 3, 9, 0, 0,
+        9, 8, 4, 8, 8, 2, 4, 0, 1, 2, 8, 5, 8, 3, 6, 1, 6, 0, 3, 5, 6, 3, 7, 0, 7, 6, 6, 0, 1, 0, 4, 7, 1, 0, 1, 8, 1, 9, 4, 2, 9, 5, 5, 5, 9, 6, 1, 9, 8, 9, 4, 6, 7, 6, 7, 8, 3, 7, 4, 4, 9, 4, 4, 8, 2, 5, 5, 3, 7, 9,
+        7, 7, 4, 7, 2, 6, 8, 4, 7, 1, 0, 4, 0, 4, 7, 5, 3, 4, 6, 4, 6, 2, 0, 8, 0, 4, 6, 6, 8, 4, 2, 5, 9, 0, 6, 9, 4, 9, 1, 2, 9, 3, 3, 1, 3, 6, 7, 7, 0, 2, 8, 9, 8, 9, 1, 5, 2, 1, 0, 4, 7, 5, 2, 1, 6, 2, 0, 5, 6, 9,
+        6, 6, 0, 2, 4, 0, 5, 8, 0, 3, 8, 1, 5, 0, 1, 9, 3, 5, 1, 1, 2, 5, 3, 3, 8, 2, 4, 3, 0, 0, 3, 5, 5, 8, 7, 6, 4, 0, 2, 4, 7, 4, 9, 6, 4, 7, 3, 2, 6, 3, 9, 1, 4, 1, 9, 9, 2, 7, 2, 6, 0, 4, 2, 6, 9, 9, 2, 2, 7, 9,
+        6, 7, 8, 2, 3, 5, 4, 7, 8, 1, 6, 3, 6, 0, 0, 9, 3, 4, 1, 7, 2, 1, 6, 4, 1, 2, 1, 9, 9, 2, 4, 5, 8, 6, 3, 1, 5, 0, 3, 0, 2, 8, 6, 1, 8, 2, 9, 7, 4, 5, 5, 5, 7, 0, 6, 7, 4, 9, 8, 3, 8, 5, 0, 5, 4, 9, 4, 5, 8, 8,
+        5, 8, 6, 9, 2, 6, 9, 9, 5, 6, 9, 0, 9, 2, 7, 2, 1, 0, 7, 9, 7, 5, 0, 9, 3, 0, 2, 9, 5, 5, 3, 2, 1, 1, 6, 5, 3, 4, 4, 9, 8, 7, 2, 0, 2, 7, 5, 5, 9, 6, 0, 2, 3, 6, 4, 8, 0, 6, 6, 5, 4, 9, 9, 1, 1, 9, 8, 8, 1, 8,
+        3, 4, 7, 9, 7, 7, 5, 3, 5, 6, 6, 3, 6, 9, 8, 0, 7, 4, 2, 6, 5, 4, 2, 5, 2, 7, 8, 6, 2, 5, 5, 1, 8, 1, 8, 4, 1, 7, 5, 7, 4, 6, 7, 2, 8, 9, 0, 9, 7, 7, 7, 7, 2, 7, 9, 3, 8, 0, 0, 0, 8, 1, 6, 4, 7, 0, 6, 0, 0, 1,
+        6, 1, 4, 5, 2, 4, 9, 1, 9, 2, 1, 7, 3, 2, 1, 7, 2, 1, 4, 7, 7, 2, 3, 5, 0, 1, 4, 1, 4, 4, 1, 9, 7, 3, 5, 6, 8, 5, 4, 8, 1, 6, 1, 3, 6, 1, 1, 5, 7, 3, 5, 2, 5, 5, 2, 1, 3, 3, 4, 7, 5, 7, 4, 1, 8, 4, 9, 4, 6, 8,
+        4, 3, 8, 5, 2, 3, 3, 2, 3, 9, 0, 7, 3, 9, 4, 1, 4, 3, 3, 3, 4, 5, 4, 7, 7, 6, 2, 4, 1, 6, 8, 6, 2, 5, 1, 8, 9, 8, 3, 5, 6, 9, 4, 8, 5, 5, 6, 2, 0, 9, 9, 2, 1, 9, 2, 2, 2, 1, 8, 4, 2, 7, 2, 5, 5, 0, 2, 5, 4, 2,
+        5, 6, 8, 8, 7, 6, 7, 1, 7, 9, 0, 4, 9, 4, 6, 0, 1, 6, 5, 3, 4, 6, 6, 8, 0, 4, 9, 8, 8, 6, 2, 7, 2, 3, 2, 7, 9, 1, 7, 8, 6, 0, 8, 5, 7, 8, 4, 3, 8, 3, 8, 2, 7, 9, 6, 7, 9, 7, 6, 6, 8, 1, 4, 5, 4, 1, 0, 0, 9, 5,
+        3, 8, 8, 3, 7, 8, 6, 3, 6, 0, 9, 5, 0, 6, 8, 0, 0, 6, 4, 2, 2, 5, 1, 2, 5, 2, 0, 5, 1, 1, 7, 3, 9, 2, 9, 8, 4, 8, 9, 6, 0, 8, 4, 1, 2, 8, 4, 8, 8, 6, 2, 6, 9, 4, 5, 6, 0, 4, 2, 4, 1, 9, 6, 5, 2, 8, 5, 0, 2, 2,
+        2, 1, 0, 6, 6, 1, 1, 8, 6, 3, 0, 6, 7, 4, 4, 2, 7, 8, 6, 2, 2, 0, 3, 9, 1, 9, 4, 9, 4, 5, 0, 4, 7, 1, 2, 3, 7, 1, 3, 7, 8, 6, 9, 6, 0, 9, 5, 6, 3, 6, 4, 3, 7, 1, 9, 1, 7, 2, 8, 7, 4, 6, 7, 7, 6, 4, 6, 5, 7, 5,
+        7, 3, 9, 6, 2, 4, 1, 3, 8, 9, 0, 8, 6, 5, 8, 3, 2, 6, 4, 5, 9, 9, 5, 8, 1, 3, 3, 9, 0, 4, 7, 8, 0, 2, 7, 5, 9, 0, 0, 9, 9, 4, 6, 5, 7, 6, 4, 0, 7, 8, 9, 5, 1, 2, 6, 9, 4, 6, 8, 3, 9, 8, 3, 5, 2, 5, 9, 5, 7, 0,
+        9, 8, 2, 5, 8, 2, 2, 6, 2, 0, 5, 2, 2, 4, 8, 9, 4, 0, 7, 7, 2, 6, 7, 1, 9, 4, 7, 8, 2, 6, 8, 4, 8, 2, 6, 0, 1, 4, 7, 6, 9, 9, 0, 9, 0, 2, 6, 4, 0, 1, 3, 6, 3, 9, 4, 4, 3, 7, 4, 5, 5, 3, 0, 5, 0, 6, 8, 2, 0, 3,
+        4, 9, 6, 2, 5, 2, 4, 5, 1, 7, 4, 9, 3, 9, 9, 6, 5, 1, 4, 3, 1, 4, 2, 9, 8, 0, 9, 1, 9, 0, 6, 5, 9, 2, 5, 0, 9, 3, 7, 2, 2, 1, 6, 9, 6, 4, 6, 1, 5, 1, 5, 7, 0, 9, 8, 5, 8, 3, 8, 7, 4, 1, 0, 5, 9, 7, 8, 8, 5, 9,
+        5, 9, 7, 7, 2, 9, 7, 5, 4, 9, 8, 9, 3, 0, 1, 6, 1, 7, 5, 3, 9, 2, 8, 4, 6, 8, 1, 3, 8, 2, 6, 8, 6, 8, 3, 8, 6, 8, 9, 4, 2, 7, 7, 4, 1, 5, 5, 9, 9, 1, 8, 5, 5, 9, 2, 5, 2, 4, 5, 9, 5, 3, 9, 5, 9, 4, 3, 1, 0, 4,
+        9, 9, 7, 2, 5, 2, 4, 6, 8, 0, 8, 4, 5, 9, 8, 7, 2, 7, 3, 6, 4, 4, 6, 9, 5, 8, 4, 8, 6, 5, 3, 8, 3, 6, 7, 3, 6, 2, 2, 2, 6, 2, 6, 0, 9, 9, 1, 2, 4, 6, 0, 8, 0, 5, 1, 2, 4, 3, 8, 8, 4, 3, 9, 0, 4, 5, 1, 2, 4, 4,
+        1, 3, 6, 5, 4, 9, 7, 6, 2, 7, 8, 0, 7, 9, 7, 7, 1, 5, 6, 9, 1, 4, 3, 5, 9, 9, 7, 7, 0, 0, 1, 2, 9, 6, 1, 6, 0, 8, 9, 4, 4, 1, 6, 9, 4, 8, 6, 8, 5, 5, 5, 8, 4, 8, 4, 0, 6, 3, 5, 3, 4, 2, 2, 0, 7, 2, 2, 2, 5, 8,
+        2, 8, 4, 8, 8, 6, 4, 8, 1, 5, 8, 4, 5, 6, 0, 2, 8, 5, 0, 6, 0, 1, 6, 8, 4, 2, 7, 3, 9, 4, 5, 2, 2, 6, 7, 4, 6, 7, 6, 7, 8, 8, 9, 5, 2, 5, 2, 1, 3, 8, 5, 2, 2, 5, 4, 9, 9, 5, 4, 6, 6, 6, 7, 2, 7, 8, 2, 3, 9, 8,
+        6, 4, 5, 6, 5, 9, 6, 1, 1, 6, 3, 5, 4, 8, 8, 6, 2, 3, 0, 5, 7, 7, 4, 5, 6, 4, 9, 8, 0, 3, 5, 5, 9, 3, 6, 3, 4, 5, 6, 8, 1, 7, 4, 3, 2, 4, 1, 1, 2, 5, 1, 5, 0, 7, 6, 0, 6, 9, 4, 7, 9, 4, 5, 1, 0, 9, 6, 5, 9, 6,
+        0, 9, 4, 0, 2, 5, 2, 2, 8, 8, 7, 9, 7, 1, 0, 8, 9, 3, 1, 4, 5, 6, 6, 9, 1, 3, 6, 8, 6, 7, 2, 2, 8, 7, 4, 8, 9, 4, 0, 5, 6, 0, 1, 0, 1, 5, 0, 3, 3, 0, 8, 6, 1, 7, 9, 2, 8, 6, 8, 0, 9, 2, 0, 8, 7, 4, 7, 6, 0, 9,
+        1, 7, 8, 2, 4, 9, 3, 8, 5, 8, 9, 0, 0, 9, 7, 1, 4, 9, 0, 9, 6, 7, 5, 9, 8, 5, 2, 6, 1, 3, 6, 5, 5, 4, 9, 7, 8, 1, 8, 9, 3, 1, 2, 9, 7, 8, 4, 8, 2, 1, 6, 8, 2, 9, 9, 8, 9, 4, 8, 7, 2, 2, 6, 5, 8, 8, 0, 4, 8, 5,
+        7, 5, 6, 4, 0, 1, 4, 2, 7, 0, 4, 7, 7, 5, 5, 5, 1, 3, 2, 3, 7, 9, 6, 4, 1, 4, 5, 1, 5, 2, 3, 7, 4, 6, 2, 3, 4, 3, 6, 4, 5, 4, 2, 8, 5, 8, 4, 4, 4, 7, 9, 5, 2, 6, 5, 8, 6, 7, 8, 2, 1, 0, 5, 1, 1, 4, 1, 3, 5, 4,
+        7, 3, 5, 7, 3, 9, 5, 2, 3, 1, 1, 3, 4, 2, 7, 1, 6, 6, 1, 0, 2, 1, 3, 5, 9, 6, 9, 5, 3, 6, 2, 3, 1, 4, 4, 2, 9, 5, 2, 4, 8, 4, 9, 3, 7, 1, 8, 7, 1, 1, 0, 1, 4, 5, 7, 6, 5, 4, 0, 3, 5, 9, 0, 2, 7, 9, 9, 3, 4, 4,
+        0, 3, 7, 4, 2, 0, 0, 7, 3, 1, 0, 5, 7, 8, 5, 3, 9, 0, 6, 2, 1, 9, 8, 3, 8, 7, 4, 4, 7, 8, 0, 8, 4, 7, 8, 4, 8, 9, 6, 8, 3, 3, 2, 1, 4, 4, 5, 7, 1, 3, 8, 6, 8, 7, 5, 1, 9, 4, 3, 5, 0, 6, 4, 3, 0, 2, 1, 8, 4, 5,
+        3, 1, 9, 1, 0, 4, 8, 4, 8, 1, 0, 0, 5, 3, 7, 0, 6, 1, 4, 6, 8, 0, 6, 7, 4, 9, 1, 9, 2, 7, 8, 1, 9, 1, 1, 9, 7, 9, 3, 9, 9, 5, 2, 0, 6, 1, 4, 1, 9, 6, 6, 3, 4, 2, 8, 7, 5, 4, 4, 4, 0, 6, 4, 3, 7, 4, 5, 1, 2, 3,
+        7, 1, 8, 1, 9, 2, 1, 7, 9, 9, 9, 8, 3, 9, 1, 0, 1, 5, 9, 1, 9, 5, 6, 1, 8, 1, 4, 6, 7, 5, 1, 4, 2, 6, 9, 1, 2, 3, 9, 7, 4, 8, 9, 4, 0, 9, 0, 7, 1, 8, 6, 4, 9, 4, 2, 3, 1, 9, 6, 1, 5, 6, 7, 9, 4, 5, 2, 0, 8, 0,
+        9, 5, 1, 4, 6, 5, 5, 0, 2, 2, 5, 2, 3, 1, 6, 0, 3, 8, 8, 1, 9, 3, 0, 1, 4, 2, 0, 9, 3, 7, 6, 2, 1, 3, 7, 8, 5, 5, 9, 5, 6, 6, 3, 8, 9, 3, 7, 7, 8, 7, 0, 8, 3, 0, 3, 9, 0, 6, 9, 7, 9, 2, 0, 7, 7, 3, 4, 6, 7, 2,
+        2, 1, 8, 2, 5, 6, 2, 5, 9, 9, 6, 6, 1, 5, 0, 1, 4, 2, 1, 5, 0, 3, 0, 6, 8, 0, 3, 8, 4, 4, 7, 7, 3, 4, 5, 4, 9, 2, 0, 2, 6, 0, 5, 4, 1, 4, 6, 6, 5, 9, 2, 5, 2, 0, 1, 4, 9, 7, 4, 4, 2, 8, 5, 0, 7, 3, 2, 5, 1, 8,
+        6, 6, 6, 0, 0, 2, 1, 3, 2, 4, 3, 4, 0, 8, 8, 1, 9, 0, 7, 1, 0, 4, 8, 6, 3, 3, 1, 7, 3, 4, 6, 4, 9, 6, 5, 1, 4, 5, 3, 9, 0, 5, 7, 9, 6, 2, 6, 8, 5, 6, 1, 0, 0, 5, 5, 0, 8, 1, 0, 6, 6, 5, 8, 7, 9, 6, 9, 9, 8, 1,
+        6, 3, 5, 7, 4, 7, 3, 6, 3, 8, 4, 0, 5, 2, 5, 7, 1, 4, 5, 9, 1, 0, 2, 8, 9, 7, 0, 6, 4, 1, 4, 0, 1, 1, 0, 9, 7, 1, 2, 0, 6, 2, 8, 0, 4, 3, 9, 0, 3, 9, 7, 5, 9, 5, 1, 5, 6, 7, 7, 1, 5, 7, 7, 0, 0, 4, 2, 0, 3, 3,
+        7, 8, 6, 9, 9, 3, 6, 0, 0, 7, 2, 3, 0, 5, 5, 8, 7, 6, 3, 1, 7, 6, 3, 5, 9, 4, 2, 1, 8, 7, 3, 1, 2, 5, 1, 4, 7, 1, 2, 0, 5, 3, 2, 9, 2, 8, 1, 9, 1, 8, 2, 6, 1, 8, 6, 1, 2, 5, 8, 6, 7, 3, 2, 1, 5, 7, 9, 1, 9, 8,
+        4, 1, 4, 8, 4, 8, 8, 2, 9, 1, 6, 4, 4, 7, 0, 6, 0, 9, 5, 7, 5, 2, 7, 0, 6, 9, 5, 7, 2, 2, 0, 9, 1, 7, 5, 6, 7, 1, 1, 6, 7, 2, 2, 9, 1, 0, 9, 8, 1, 6, 9, 0, 9, 1, 5, 2, 8, 0, 1, 7, 3, 5, 0, 6, 7, 1, 2, 7, 4, 8,
+        5, 8, 3, 2, 2, 2, 8, 7, 1, 8, 3, 5, 2, 0, 9, 3, 5, 3, 9, 6, 5, 7, 2, 5, 1, 2, 1, 0, 8, 3, 5, 7, 9, 1, 5, 1, 3, 6, 9, 8, 8, 2, 0, 9, 1, 4, 4, 4, 2, 1, 0, 0, 6, 7, 5, 1, 0, 3, 3, 4, 6, 7, 1, 1, 0, 3, 1, 4, 1, 2,
+        6, 7, 1, 1, 1, 3, 6, 9, 9, 0, 8, 6, 5, 8, 5, 1, 6, 3, 9, 8, 3, 1, 5, 0, 1, 9, 7, 0, 1, 6, 5, 1, 5, 1, 1, 6, 8, 5, 1, 7, 1, 4, 3, 7, 6, 5, 7, 6, 1, 8, 3, 5, 1, 5, 5, 6, 5, 0, 8, 8, 4, 9, 0, 9, 9, 8, 9, 8, 5, 9,
+        9, 8, 2, 3, 8, 7, 3, 4, 5, 5, 2, 8, 3, 3, 1, 6, 3, 5, 5, 0, 7, 6, 4, 7, 9, 1, 8, 5, 3, 5, 8, 9, 3, 2, 2, 6, 1, 8, 5, 4, 8, 9, 6, 3, 2, 1, 3, 2, 9, 3, 3, 0, 8, 9, 8, 5, 7, 0, 6, 4, 2, 0, 4, 6, 7, 5, 2, 5, 9, 0,
+        7, 0, 9, 1, 5, 4, 8, 1, 4, 1, 6, 5, 4, 9, 8, 5, 9, 4, 6, 1, 6, 3, 7, 1, 8, 0, 2, 7, 0, 9, 8, 1, 9, 9, 4, 3, 0, 9, 9, 2, 4, 4, 8, 8, 9, 5, 7, 5, 7, 1, 2, 8, 2, 8, 9, 0, 5, 9, 2, 3, 2, 3, 3, 2, 6, 0, 9, 7, 2, 9,
+        9, 7, 1, 2, 0, 8, 4, 4, 3, 3, 5, 7, 3, 2, 6, 5, 4, 8, 9, 3, 8, 2, 3, 9, 1, 1, 9, 3, 2, 5, 9, 7, 4, 6, 3, 6, 6, 7, 3, 0, 5, 8, 3, 6, 0, 4, 1, 4, 2, 8, 1, 3, 8, 8, 3, 0, 3, 2, 0, 3, 8, 2, 4, 9, 0, 3, 7, 5, 8, 9,
+        8, 5, 2, 4, 3, 7, 4, 4, 1, 7, 0, 2, 9, 1, 3, 2, 7, 6, 5, 6, 1, 8, 0, 9, 3, 7, 7, 3, 4, 4, 4, 0, 3, 0, 7, 0, 7, 4, 6, 9, 2, 1, 1, 2, 0, 1, 9, 1, 3, 0, 2, 0, 3, 3, 0, 3, 8, 0, 1, 9, 7, 6, 2, 1, 1, 0, 1, 1, 0, 0,
+        4, 4, 9, 2, 9, 3, 2, 1, 5, 1, 6, 0, 8, 4, 2, 4, 4, 4, 8, 5, 9, 6, 3, 7, 6, 6, 9, 8, 3, 8, 9, 5, 2, 2, 8, 6, 8, 4, 7, 8, 3, 1, 2, 3, 5, 5, 2, 6, 5, 8, 2, 1, 3, 1, 4, 4, 9, 5, 7, 6, 8, 5, 7, 2, 6, 2, 4, 3, 3, 4,
+        4, 1, 8, 9, 3, 0, 3, 9, 6, 8, 6, 4, 2, 6, 2, 4, 3, 4, 1, 0, 7, 7, 3, 2, 2, 6, 9, 7, 8, 0, 2, 8, 0, 7, 3, 1, 8, 9, 1, 5, 4, 4, 1, 1, 0, 1, 0, 4, 4, 6, 8, 2, 3, 2, 5, 2, 7, 1, 6, 2, 0, 1, 0, 5, 2, 6, 5, 2, 2, 7,
+        2, 1, 1, 1, 6, 6, 0, 3, 9, 6, 6, 6, 5, 5, 7, 3, 0, 9, 2, 5, 4, 7, 1, 1, 0, 5, 5, 7, 8, 5, 3, 7, 6, 3, 4, 6, 6, 8, 2, 0, 6, 5, 3, 1, 0, 9, 8, 9, 6, 5, 2, 6, 9, 1, 8, 6, 2, 0, 5, 6, 4, 7, 6, 9, 3, 1, 2, 5, 7, 0,
+        5, 8, 6, 3, 5, 6, 6, 2, 0, 1, 8, 5, 5, 8, 1, 0, 0, 7, 2, 9, 3, 6, 0, 6, 5, 9, 8, 7, 6, 4, 8, 6, 1, 1, 7, 9, 1, 0, 4, 5, 3, 3, 4, 8, 8, 5, 0, 3, 4, 6, 1, 1, 3, 6, 5, 7, 6, 8, 6, 7, 5, 3, 2, 4, 9, 4, 4, 1, 6, 6,
+        8, 0, 3, 9, 6, 2, 6, 5, 7, 9, 7, 8, 7, 7, 1, 8, 5, 5, 6, 0, 8, 4, 5, 5, 2, 9, 6, 5, 4, 1, 2, 6, 6, 5, 4, 0, 8, 5, 3, 0, 6, 1, 4, 3, 4, 4, 4, 3, 1, 8, 5, 8, 6, 7, 6, 9, 7, 5, 1, 4, 5, 6, 6, 1, 4, 0, 6, 8, 0, 0,
+        7, 0, 0, 2, 3, 7, 8, 7, 7, 6, 5, 9, 1, 3, 4, 4, 0, 1, 7, 1, 2, 7, 4, 9, 4, 7, 0, 4, 2, 0, 5, 6, 2, 2, 3, 0, 5, 3, 8, 9, 9, 4, 5, 6, 1, 3, 1, 4, 0, 7, 1, 1, 2, 7, 0, 0, 0, 4, 0, 7, 8, 5, 4, 7, 3, 3, 2, 6, 9, 9,
+        3, 9, 0, 8, 1, 4, 5, 4, 6, 6, 4, 6, 4, 5, 8, 8, 0, 7, 9, 7, 2, 7, 0, 8, 2, 6, 6, 8, 3, 0, 6, 3, 4, 3, 2, 8, 5, 8, 7, 8, 5, 6, 9, 8, 3, 0, 5, 2, 3, 5, 8, 0, 8, 9, 3, 3, 0, 6, 5, 7, 5, 7, 4, 0, 6, 7, 9, 5, 4, 5,
+        7, 1, 6, 3, 7, 7, 5, 2, 5, 4, 2, 0, 2, 1, 1, 4, 9, 5, 5, 7, 6, 1, 5, 8, 1, 4, 0, 0, 2, 5, 0, 1, 2, 6, 2, 2, 8, 5, 9, 4, 1, 3, 0, 2, 1, 6, 4, 7, 1, 5, 5, 0, 9, 7, 9, 2, 5, 9, 2, 3, 0, 9, 9, 0, 7, 9, 6, 5, 4, 7,
+        3, 7, 6, 1, 2, 5, 5, 1, 7, 6, 5, 6, 7, 5, 1, 3, 5, 7, 5, 1, 7, 8, 2, 9, 6, 6, 6, 4, 5, 4, 7, 7, 9, 1, 7, 4, 5, 0, 1, 1, 2, 9, 9, 6, 1, 4, 8, 9, 0, 3, 0, 4, 6, 3, 9, 9, 4, 7, 1, 3, 2, 9, 6, 2, 1, 0, 7, 3, 4, 0,
+        4, 3, 7, 5, 1, 8, 9, 5, 7, 3, 5, 9, 6, 1, 4, 5, 8, 9, 0, 1, 9, 3, 8, 9, 7, 1, 3, 1, 1, 1, 7, 9, 0, 4, 2, 9, 7, 8, 2, 8, 5, 6, 4, 7, 5, 0, 3, 2, 0, 3, 1, 9, 8, 6, 9, 1, 5, 1, 4, 0, 2, 8, 7, 0, 8, 0, 8, 5, 9, 9,
+        0, 4, 8, 0, 1, 0, 9, 4, 1, 2, 1, 4, 7, 2, 2, 1, 3, 1, 7, 9, 4, 7, 6, 4, 7, 7, 7, 2, 6, 2, 2, 4, 1, 4, 2, 5, 4, 8, 5, 4, 5, 4, 0, 3, 3, 2, 1, 5, 7, 1, 8, 5, 3, 0, 6, 1, 4, 2, 2, 8, 8, 1, 3, 7, 5, 8, 5, 0, 4, 3,
+        0, 6, 3, 3, 2, 1, 7, 5, 1, 8, 2, 9, 7, 9, 8, 6, 6, 2, 2, 3, 7, 1, 7, 2, 1, 5, 9, 1, 6, 0, 7, 7, 1, 6, 6, 9, 2, 5, 4, 7, 4, 8, 7, 3, 8, 9, 8, 6, 6, 5, 4, 9, 4, 9, 4, 5, 0, 1, 1, 4, 6, 5, 4, 0, 6, 2, 8, 4, 3, 3,
+        6, 6, 3, 9, 3, 7, 9, 0, 0, 3, 9, 7, 6, 9, 2, 6, 5, 6, 7, 2, 1, 4, 6, 3, 8, 5, 3, 0, 6, 7, 3, 6, 0, 9, 6, 5, 7, 1, 2, 0, 9, 1, 8, 0, 7, 6, 3, 8, 3, 2, 7, 1, 6, 6, 4, 1, 6, 2, 7, 4, 8, 8, 8, 8, 0, 0, 7, 8, 6, 9,
+        2, 5, 6, 0, 2, 9, 0, 2, 2, 8, 4, 7, 2, 1, 0, 4, 0, 3, 1, 7, 2, 1, 1, 8, 6, 0, 8, 2, 0, 4, 1, 9, 0, 0, 0, 4, 2, 2, 9, 6, 6, 1, 7, 1, 1, 9, 6, 3, 7, 7, 9, 2, 1, 3, 3, 7, 5, 7, 5, 1, 1, 4, 9, 5, 9, 5, 0, 1, 5, 6,
+        6, 0, 4, 9, 6, 3, 1, 8, 6, 2, 9, 4, 7, 2, 6, 5, 4, 7, 3, 6, 4, 2, 5, 2, 3, 0, 8, 1, 7, 7, 0, 3, 6, 7, 5, 1, 5, 9, 0, 6, 7, 3, 5, 0, 2, 3, 5, 0, 7, 2, 8, 3, 5, 4, 0, 5, 6, 7, 0, 4, 0, 3, 8, 6, 7, 4, 3, 5, 1, 3,
+        6, 2, 2, 2, 2, 4, 7, 7, 1, 5, 8, 9, 1, 5, 0, 4, 9, 5, 3, 0, 9, 8, 4, 4, 4, 8, 9, 3, 3, 3, 0, 9, 6, 3, 4, 0, 8, 7, 8, 0, 7, 6, 9, 3, 2, 5, 9, 9, 3, 9, 7, 8, 0, 5, 4, 1, 9, 3, 4, 1, 4, 4, 7, 3, 7, 7, 4, 4, 1, 8,
+        4, 2, 6, 3, 1, 2, 9, 8, 6, 0, 8, 0, 9, 9, 8, 8, 8, 6, 8, 7, 4, 1, 3, 2, 6, 0, 4, 7, 2, 1, 5, 6, 9, 5, 1, 6, 2, 3, 9, 6, 5, 8, 6, 4, 5, 7, 3, 0, 2, 1, 6, 3, 1, 5, 9, 8, 1, 9, 3, 1, 9, 5, 1, 6, 7, 3, 5, 3, 8, 1,
+        2, 9, 7, 4, 1, 6, 7, 7, 2, 9, 4, 7, 8, 6, 7, 2, 4, 2, 2, 9, 2, 4, 6, 5, 4, 3, 6, 6, 8, 0, 0, 9, 8, 0, 6, 7, 6, 9, 2, 8, 2, 3, 8, 2, 8, 0, 6, 8, 9, 9, 6, 4, 0, 0, 4, 8, 2, 4, 3, 5, 4, 0, 3, 7, 0, 1, 4, 1, 6, 3,
+        1, 4, 9, 6, 5, 8, 9, 7, 9, 4, 0, 9, 2, 4, 3, 2, 3, 7, 8, 9, 6, 9, 0, 7, 0, 6, 9, 7, 7, 9, 4, 2, 2, 3, 6, 2, 5, 0, 8, 2, 2, 1, 6, 8, 8, 9, 5, 7, 3, 8, 3, 7, 9, 8, 6, 2, 3, 0, 0, 1, 5, 9, 3, 7, 7, 6, 4, 7, 1, 6,
+        5, 1, 2, 2, 8, 9, 3, 5, 7, 8, 6, 0, 1, 5, 8, 8, 1, 6, 1, 7, 5, 5, 7, 8, 2, 9, 7, 3, 5, 2, 3, 3, 4, 4, 6, 0, 4, 2, 8, 1, 5, 1, 2, 6, 2, 7, 2, 0, 3, 7, 3, 4, 3, 1, 4, 6, 5, 3, 1, 9, 7, 7, 7, 7, 4, 1, 6, 0, 3, 1,
+        9, 9, 0, 6, 6, 5, 5, 4, 1, 8, 7, 6, 3, 9, 7, 9, 2, 9, 3, 3, 4, 4, 1, 9, 5, 2, 1, 5, 4, 1, 3, 4, 1, 8, 9, 9, 4, 8, 5, 4, 4, 4, 7, 3, 4, 5, 6, 7, 3, 8, 3, 1, 6, 2, 4, 9, 9, 3, 4, 1, 9, 1, 3, 1, 8, 1, 4, 8, 0, 9,
+        2, 7, 7, 7, 7, 1, 0, 3, 8, 6, 3, 8, 7, 7, 3, 4, 3, 1, 7, 7, 2, 0, 7, 5, 4, 5, 6, 5, 4, 5, 3, 2, 2, 0, 7, 7, 7, 0, 9, 2, 1, 2, 0, 1, 9, 0, 5, 1, 6, 6, 0, 9, 6, 2, 8, 0, 4, 9, 0, 9, 2, 6, 3, 6, 0, 1, 9, 7, 5, 9,
+        8, 8, 2, 8, 1, 6, 1, 3, 3, 2, 3, 1, 6, 6, 6, 3, 6, 5, 2, 8, 6, 1, 9, 3, 2, 6, 6, 8, 6, 3, 3, 6, 0, 6, 2, 7, 3, 5, 6, 7, 6, 3, 0, 3, 5, 4, 4, 7, 7, 6, 2, 8, 0, 3, 5, 0, 4, 5, 0, 7, 7, 7, 2, 3, 5, 5, 4, 7, 1, 0,
+        5, 8, 5, 9, 5, 4, 8, 7, 0, 2, 7, 9, 0, 8, 1, 4, 3, 5, 6, 2, 4, 0, 1, 4, 5, 1, 7, 1, 8, 0, 6, 2, 4, 6, 4, 3, 6, 2, 6, 7, 9, 4, 5, 6, 1, 2, 7, 5, 3, 1, 8, 1, 3, 4, 0, 7, 8, 3, 3, 0, 3, 3, 6, 2, 5, 4, 2, 3, 2, 7,
+        8, 3, 9, 4, 4, 9, 7, 5, 3, 8, 2, 4, 3, 7, 2, 0, 5, 8, 3, 5, 3, 1, 1, 4, 7, 7, 1, 1, 9, 9, 2, 6, 0, 6, 3, 8, 1, 3, 3, 4, 6, 7, 7, 6, 8, 7, 9, 6, 9, 5, 9, 7, 0, 3, 0, 9, 8, 3, 3, 9, 1, 3, 0, 7, 7, 1, 0, 9, 8, 7,
+        0, 4, 0, 8, 5, 9, 1, 3, 3, 7, 4, 6, 4, 1, 4, 4, 2, 8, 2, 2, 7, 7, 2, 6, 3, 4, 6, 5, 9, 4, 7, 0, 4, 7, 4, 5, 8, 7, 8, 4, 7, 7, 8, 7, 2, 0, 1, 9, 2, 7, 7, 1, 5, 2, 8, 0, 7, 3, 1, 7, 6, 7, 9, 0, 7, 7, 0, 7, 1, 5,
+        7, 2, 1, 3, 4, 4, 4, 7, 3, 0, 6, 0, 5, 7, 0, 0, 7, 3, 3, 4, 9, 2, 4, 3, 6, 9, 3, 1, 1, 3, 8, 3, 5, 0, 4, 9, 3, 1, 6, 3, 1, 2, 8, 4, 0, 4, 2, 5, 1, 2, 1, 9, 2, 5, 6, 5, 1, 7, 9, 8, 0, 6, 9, 4, 1, 1, 3, 5, 2, 8,
+        0, 1, 3, 1, 4, 7, 0, 1, 3, 0, 4, 7, 8, 1, 6, 4, 3, 7, 8, 8, 5, 1, 8, 5, 2, 9, 0, 9, 2, 8, 5, 4, 5, 2, 0, 1, 1, 6, 5, 8, 3, 9, 3, 4, 1, 9, 6, 5, 6, 2, 1, 3, 4, 9, 1, 4, 3, 4, 1, 5, 9, 5, 6, 2, 5, 8, 6, 5, 8, 6,
+        5, 5, 7, 0, 5, 5, 2, 6, 9, 0, 4, 9, 6, 5, 2, 0, 9, 8, 5, 8, 0, 3, 3, 8, 5, 0, 7, 2, 2, 4, 2, 6, 4, 8, 2, 9, 3, 9, 7, 2, 8, 5, 8, 4, 7, 8, 3, 1, 6, 3, 0, 5, 7, 7, 7, 7, 5, 6, 0, 6, 8, 8, 8, 7, 6, 4, 4, 6, 2, 4,
+        8, 2, 4, 6, 8, 5, 7, 9, 2, 6, 0, 3, 9, 5, 3, 5, 2, 7, 7, 3, 4, 8, 0, 3, 0, 4, 8, 0, 2, 9, 0, 0, 5, 8, 7, 6, 0, 7, 5, 8, 2, 5, 1, 0, 4, 7, 4, 7, 0, 9, 1, 6, 4, 3, 9, 6, 1, 3, 6, 2, 6, 7, 6, 0, 4, 4, 9, 2, 5, 6,
+        2, 7, 4, 2, 0, 4, 2, 0, 8, 3, 2, 0, 8, 5, 6, 6, 1, 1, 9, 0, 6, 2, 5, 4, 5, 4, 3, 3, 7, 2, 1, 3, 1, 5, 3, 5, 9, 5, 8, 4, 5, 0, 6, 8, 7, 7, 2, 4, 6, 0, 2, 9, 0, 1, 6, 1, 8, 7, 6, 6, 7, 9, 5, 2, 4, 0, 6, 1, 6, 3,
+        4, 2, 5, 2, 2, 5, 7, 7, 1, 9, 5, 4, 2, 9, 1, 6, 2, 9, 9, 1, 9, 3, 0, 6, 4, 5, 5, 3, 7, 7, 9, 9, 1, 4, 0, 3, 7, 3, 4, 0, 4, 3, 2, 8, 7, 5, 2, 6, 2, 8, 8, 8, 9, 6, 3, 9, 9, 5, 8, 7, 9, 4, 7, 5, 7, 2, 9, 1, 7, 4,
+        6, 4, 2, 6, 3, 5, 7, 4, 5, 5, 2, 5, 4, 0, 7, 9, 0, 9, 1, 4, 5, 1, 3, 5, 7, 1, 1, 1, 3, 6, 9, 4, 1, 0, 9, 1, 1, 9, 3, 9, 3, 2, 5, 1, 9, 1, 0, 7, 6, 0, 2, 0, 8, 2, 5, 2, 0, 2, 6, 1, 8, 7, 9, 8, 5, 3, 1, 8, 8, 7,
+        7, 0, 5, 8, 4, 2, 9, 7, 2, 5, 9, 1, 6, 7, 7, 8, 1, 3, 1, 4, 9, 6, 9, 9, 0, 0, 9, 0, 1, 9, 2, 1, 1, 6, 9, 7, 1, 7, 3, 7, 2, 7, 8, 4, 7, 6, 8, 4, 7, 2, 6, 8, 6, 0, 8, 4, 9, 0, 0, 3, 3, 7, 7, 0, 2, 4, 2, 4, 2, 9,
+        1, 6, 5, 1, 3, 0, 0, 5, 0, 0, 5, 1, 6, 8, 3, 2, 3, 3, 6, 4, 3, 5, 0, 3, 8, 9, 5, 1, 7, 0, 2, 9, 8, 9, 3, 9, 2, 2, 3, 3, 4, 5, 1, 7, 2, 2, 0, 1, 3, 8, 1, 2, 8, 0, 6, 9, 6, 5, 0, 1, 1, 7, 8, 4, 4, 0, 8, 7, 4, 5,
+        1, 9, 6, 0, 1, 2, 1, 2, 2, 8, 5, 9, 9, 3, 7, 1, 6, 2, 3, 1, 3, 0, 1, 7, 1, 1, 4, 4, 4, 8, 4, 6, 4, 0, 9, 0, 3, 8, 9, 0, 6, 4, 4, 9, 5, 4, 4, 4, 0, 0, 6, 1, 9, 8, 6, 9, 0, 7, 5, 4, 8, 5, 1, 6, 0, 2, 6, 3, 2, 7,
+        5, 0, 5, 2, 9, 8, 3, 4, 9, 1, 8, 7, 4, 0, 7, 8, 6, 6, 8, 0, 8, 8, 1, 8, 3, 3, 8, 5, 1, 0, 2, 2, 8, 3, 3, 4, 5, 0, 8, 5, 0, 4, 8, 6, 0, 8, 2, 5, 0, 3, 9, 3, 0, 2, 1, 3, 3, 2, 1, 9, 7, 1, 5, 5, 1, 8, 4, 3, 0, 6,
+        3, 5, 4, 5, 5, 0, 0, 7, 6, 6, 8, 2, 8, 2, 9, 4, 9, 3, 0, 4, 1, 3, 7, 7, 6, 5, 5, 2, 7, 9, 3, 9, 7, 5, 1, 7, 5, 4, 6, 1, 3, 9, 5, 3, 9, 8, 4, 6, 8, 3, 3, 9, 3, 6, 3, 8, 3, 0, 4, 7, 4, 6, 1, 1, 9, 9, 6, 6, 5, 3,
+        8, 5, 8, 1, 5, 3, 8, 4, 2, 0, 5, 6, 8, 5, 3, 3, 8, 6, 2, 1, 8, 6, 7, 2, 5, 2, 3, 3, 4, 0, 2, 8, 3, 0, 8, 7, 1, 1, 2, 3, 2, 8, 2, 7, 8, 9, 2, 1, 2, 5, 0, 7, 7, 1, 2, 6, 2, 9, 4, 6, 3, 2, 2, 9, 5, 6, 3, 9, 8, 9,
+        8, 9, 8, 9, 3, 5, 8, 2, 1, 1, 6, 7, 4, 5, 6, 2, 7, 0, 1, 0, 2, 1, 8, 3, 5, 6, 4, 6, 2, 2, 0, 1, 3, 4, 9, 6, 7, 1, 5, 1, 8, 8, 1, 9, 0, 9, 7, 3, 0, 3, 8, 1, 1, 9, 8, 0, 0, 4, 9, 7, 3, 4, 0, 7, 2, 3, 9, 6, 1, 0,
+        3, 6, 8, 5, 4, 0, 6, 6, 4, 3, 1, 9, 3, 9, 5, 0, 9, 7, 9, 0, 1, 9, 0, 6, 9, 9, 6, 3, 9, 5, 5, 2, 4, 5, 3, 0, 0, 5, 4, 5, 0, 5, 8, 0, 6, 8, 5, 5, 0, 1, 9, 5, 6, 7, 3, 0, 2, 2, 9, 2, 1, 9, 1, 3, 9, 3, 3, 9, 1, 8,
+        5, 6, 8, 0, 3, 4, 4, 9, 0, 3, 9, 8, 2, 0, 5, 9, 5, 5, 1, 0, 0, 2, 2, 6, 3, 5, 3, 5, 3, 6, 1, 9, 2, 0, 4, 1, 9, 9, 4, 7, 4, 5, 5, 3, 8, 5, 9, 3, 8, 1, 0, 2, 3, 4, 3, 9, 5, 5, 4, 4, 9, 5, 9, 7, 7, 8, 3, 7, 7, 9,
+        0, 2, 3, 7, 4, 2, 1, 6, 1, 7, 2, 7, 1, 1, 1, 7, 2, 3, 6, 4, 3, 4, 3, 5, 4, 3, 9, 4, 7, 8, 2, 2, 1, 8, 1, 8, 5, 2, 8, 6, 2, 4, 0, 8, 5, 1, 4, 0, 0, 6, 6, 6, 0, 4, 4, 3, 3, 2, 5, 8, 8, 8, 5, 6, 9, 8, 6, 7, 0, 5,
+        4, 3, 1, 5, 4, 7, 0, 6, 9, 6, 5, 7, 4, 7, 4, 5, 8, 5, 5, 0, 3, 3, 2, 3, 2, 3, 3, 4, 2, 1, 0, 7, 3, 0, 1, 5, 4, 5, 9, 4, 0, 5, 1, 6, 5, 5, 3, 7, 9, 0, 6, 8, 6, 6, 2, 7, 3, 3, 3, 7, 9, 9, 5, 8, 5, 1, 1, 5, 6, 2,
+        5, 7, 8, 4, 3, 2, 2, 9, 8, 8, 2, 7, 3, 7, 2, 3, 1, 9, 8, 9, 8, 7, 5, 7, 1, 4, 1, 5, 9, 5, 7, 8, 1, 1, 1, 9, 6, 3, 5, 8, 3, 3, 0, 0, 5, 9, 4, 0, 8, 7, 3, 0, 6, 8, 1, 2, 1, 6, 0, 2, 8, 7, 6, 4, 9, 6, 2, 8, 6, 7,
+        4, 4, 6, 0, 4, 7, 7, 4, 6, 4, 9, 1, 5, 9, 9, 5, 0, 5, 4, 9, 7, 3, 7, 4, 2, 5, 6, 2, 6, 9, 0, 1, 0, 4, 9, 0, 3, 7, 7, 8, 1, 9, 8, 6, 8, 3, 5, 9, 3, 8, 1, 4, 6, 5, 7, 4, 1, 2, 6, 8, 0, 4, 9, 2, 5, 6, 4, 8, 7, 9,
+        8, 5, 5, 6, 1, 4, 5, 3, 7, 2, 3, 4, 7, 8, 6, 7, 3, 3, 0, 3, 9, 0, 4, 6, 8, 8, 3, 8, 3, 4, 3, 6, 3, 4, 6, 5, 5, 3, 7, 9, 4, 9, 8, 6, 4, 1, 9, 2, 7, 0, 5, 6, 3, 8, 7, 2, 9, 3, 1, 7, 4, 8, 7, 2, 3, 3, 2, 0, 8, 3,
+        7, 6, 0, 1, 1, 2, 3, 0, 2, 9, 9, 1, 1, 3, 6, 7, 9, 3, 8, 6, 2, 7, 0, 8, 9, 4, 3, 8, 7, 9, 9, 3, 6, 2, 0, 1, 6, 2, 9, 5, 1, 5, 4, 1, 3, 3, 7, 1, 4, 2, 4, 8, 9, 2, 8, 3, 0, 7, 2, 2, 0, 1, 2, 6, 9, 0, 1, 4, 7, 5,
+        4, 6, 6, 8, 4, 7, 6, 5, 3, 5, 7, 6, 1, 6, 4, 7, 7, 3, 7, 9, 4, 6, 7, 5, 2, 0, 0, 4, 9, 0, 7, 5, 7, 1, 5, 5, 5, 2, 7, 8, 1, 9, 6, 5, 3, 6, 2, 1, 3, 2, 3, 9, 2, 6, 4, 0, 6, 1, 6, 0, 1, 3, 6, 3, 5, 8, 1, 5, 5, 9,
+        0, 7, 4, 2, 2, 0, 2, 0, 2, 0, 3, 1, 8, 7, 2, 7, 7, 6, 0, 5, 2, 7, 7, 2, 1, 9, 0, 0, 5, 5, 6, 1, 4, 8, 4, 2, 5, 5, 5, 1, 8, 7, 9, 2, 5, 3, 0, 3, 4, 3, 5, 1, 3, 9, 8, 4, 4, 2, 5, 3, 2, 2, 3, 4, 1, 5, 7, 6, 2, 3,
+        3, 6, 1, 0, 6, 4, 2, 5, 0, 6, 3, 9, 0, 4, 9, 7, 5, 0, 0, 8, 6, 5, 6, 2, 7, 1, 0, 9, 5, 3, 5, 9, 1, 9, 4, 6, 5, 8, 9, 7, 5, 1, 4, 1, 3, 1, 0, 3, 4, 8, 2, 2, 7, 6, 9, 3, 0, 6, 2, 4, 7, 4, 3, 5, 3, 6, 3, 2, 5, 6,
+        9, 1, 6, 0, 7, 8, 1, 5, 4, 7, 8, 1, 8, 1, 1, 5, 2, 8, 4, 3, 6, 6, 7, 9, 5, 7, 0, 6, 1, 1, 0, 8, 6, 1, 5, 3, 3, 1, 5, 0, 4, 4, 5, 2, 1, 2, 7, 4, 7, 3, 9, 2, 4, 5, 4, 4, 9, 4, 5, 4, 2, 3, 6, 8, 2, 8, 8, 6, 0, 6,
+        1, 3, 4, 0, 8, 4, 1, 4, 8, 6, 3, 7, 7, 6, 7, 0, 0, 9, 6, 1, 2, 0, 7, 1, 5, 1, 2, 4, 9, 1, 4, 0, 4, 3, 0, 2, 7, 2, 5, 3, 8, 6, 0, 7, 6, 4, 8, 2, 3, 6, 3, 4, 1, 4, 3, 3, 4, 6, 2, 3, 5, 1, 8, 9, 7, 5, 7, 6, 6, 4,
+        5, 2, 1, 6, 4, 1, 3, 7, 6, 7, 9, 6, 9, 0, 3, 1, 4, 9, 5, 0, 1, 9, 1, 0, 8, 5, 7, 5, 9, 8, 4, 4, 2, 3, 9, 1, 9, 8, 6, 2, 9, 1, 6, 4, 2, 1, 9, 3, 9, 9, 4, 9, 0, 7, 2, 3, 6, 2, 3, 4, 6, 4, 6, 8, 4, 4, 1, 1, 7, 3,
+        9, 4, 0, 3, 2, 6, 5, 9, 1, 8, 4, 0, 4, 4, 3, 7, 8, 0, 5, 1, 3, 3, 3, 8, 9, 4, 5, 2, 5, 7, 4, 2, 3, 9, 9, 5, 0, 8, 2, 9, 6, 5, 9, 1, 2, 2, 8, 5, 0, 8, 5, 5, 5, 8, 2, 1, 5, 7, 2, 5, 0, 3, 1, 0, 7, 1, 2, 5, 7, 0,
+        1, 2, 6, 6, 8, 3, 0, 2, 4, 0, 2, 9, 2, 9, 5, 2, 5, 2, 2, 0, 1, 1, 8, 7, 2, 6, 7, 6, 7, 5, 6, 2, 2, 0, 4, 1, 5, 4, 2, 0, 5, 1, 6, 1, 8, 4, 1, 6, 3, 4, 8, 4, 7, 5, 6, 5, 1, 6, 9, 9, 9, 8, 1, 1, 6, 1, 4, 1, 0, 1,
+        0, 0, 2, 9, 9, 6, 0, 7, 8, 3, 8, 6, 9, 0, 9, 2, 9, 1, 6, 0, 3, 0, 2, 8, 8, 4, 0, 0, 2, 6, 9, 1, 0, 4, 1, 4, 0, 7, 9, 2, 8, 8, 6, 2, 1, 5, 0, 7, 8, 4, 2, 4, 5, 1, 6, 7, 0, 9, 0, 8, 7, 0, 0, 0, 6, 9, 9, 2, 8, 2,
+        1, 2, 0, 6, 6, 0, 4, 1, 8, 3, 7, 1, 8, 0, 6, 5, 3, 5, 5, 6, 7, 2, 5, 2, 5, 3, 2, 5, 6, 7, 5, 3, 2, 8, 6, 1, 2, 9, 1, 0, 4, 2, 4, 8, 7, 7, 6, 1, 8, 2, 5, 8, 2, 9, 7, 6, 5, 1, 5, 7, 9, 5, 9, 8, 4, 7, 0, 3, 5, 6,
+        2, 2, 2, 6, 2, 9, 3, 4, 8, 6, 0, 0, 3, 4, 1, 5, 8, 7, 2, 2, 9, 8, 0, 5, 3, 4, 9, 8, 9, 6, 5, 0, 2, 2, 6, 2, 9, 1, 7, 4, 8, 7, 8, 8, 2, 0, 2, 7, 3, 4, 2, 0, 9, 2, 2, 2, 2, 4, 5, 3, 3, 9, 8, 5, 6, 2, 6, 4, 7, 6,
+        6, 9, 1, 4, 9, 0, 5, 5, 6, 2, 8, 4, 2, 5, 0, 3, 9, 1, 2, 7, 5, 7, 7, 1, 0, 2, 8, 4, 0, 2, 7, 9, 9, 8, 0, 6, 6, 3, 6, 5, 8, 2, 5, 4, 8, 8, 9, 2, 6, 4, 8, 8, 0, 2, 5, 4, 5, 6, 6, 1, 0, 1, 7, 2, 9, 6, 7, 0, 2, 6,
+        6, 4, 0, 7, 6, 5, 5, 9, 0, 4, 2, 9, 0, 9, 9, 4, 5, 6, 8, 1, 5, 0, 6, 5, 2, 6, 5, 3, 0, 5, 3, 7, 1, 8, 2, 9, 4, 1, 2, 7, 0, 3, 3, 6, 9, 3, 1, 3, 7, 8, 5, 1, 7, 8, 6, 0, 9, 0, 4, 0, 7, 0, 8, 6, 6, 7, 1, 1, 4, 9,
+        6, 5, 5, 8, 3, 4, 3, 4, 3, 4, 7, 6, 9, 3, 3, 8, 5, 7, 8, 1, 7, 1, 1, 3, 8, 6, 4, 5, 5, 8, 7, 3, 6, 7, 8, 1, 2, 3, 0, 1, 4, 5, 8, 7, 6, 8, 7, 1, 2, 6, 6, 0, 3, 4, 8, 9, 1, 3, 9, 0, 9, 5, 6, 2, 0, 0, 9, 9, 3, 9,
+        3, 6, 1, 0, 3, 1, 0, 2, 9, 1, 6, 1, 6, 1, 5, 2, 8, 8, 1, 3, 8, 4, 3, 7, 9, 0, 9, 9, 0, 4, 2, 3, 1, 7, 4, 7, 3, 3, 6, 3, 9, 4, 8, 0, 4, 5, 7, 5, 9, 3, 1, 4, 9, 3, 1, 4, 0, 5, 2, 9, 7, 6, 3, 4, 7, 5, 7, 4, 8, 1,
+        1, 9, 3, 5, 6, 7, 0, 9, 1, 1, 0, 1, 3, 7, 7, 5, 1, 7, 2, 1, 0, 0, 8, 0, 3, 1, 5, 5, 9, 0, 2, 4, 8, 5, 3, 0, 9, 0, 6, 6, 9, 2, 0, 3, 7, 6, 7, 1, 9, 2, 2, 0, 3, 3, 2, 2, 9, 0, 9, 4, 3, 3, 4, 6, 7, 6, 8, 5, 1, 4,
+        2, 2, 1, 4, 4, 7, 7, 3, 7, 9, 3, 9, 3, 7, 5, 1, 7, 0, 3, 4, 4, 3, 6, 6, 1, 9, 9, 1, 0, 4, 0, 3, 3, 7, 5, 1, 1, 1, 7, 3, 5, 4, 7, 1, 9, 1, 8, 5, 5, 0, 4, 6, 4, 4, 9, 0, 2, 6, 3, 6, 5, 5, 1, 2, 8, 1, 6, 2, 2, 8,
+        8, 2, 4, 4, 6, 2, 5, 7, 5, 9, 1, 6, 3, 3, 3, 0, 3, 9, 1, 0, 7, 2, 2, 5, 3, 8, 3, 7, 4, 2, 1, 8, 2, 1, 4, 0, 8, 8, 3, 5, 0, 8, 6, 5, 7, 3, 9, 1, 7, 7, 1, 5, 0, 9, 6, 8, 2, 8, 8, 7, 4, 7, 8, 2, 6, 5, 6, 9, 9, 5,
+        9, 9, 5, 7, 4, 4, 9, 0, 6, 6, 1, 7, 5, 8, 3, 4, 4, 1, 3, 7, 5, 2, 2, 3, 9, 7, 0, 9, 6, 8, 3, 4, 0, 8, 0, 0, 5, 3, 5, 5, 9, 8, 4, 9, 1, 7, 5, 4, 1, 7, 3, 8, 1, 8, 8, 3, 9, 9, 9, 4, 4, 6, 9, 7, 4, 8, 6, 7, 6, 2,
+        6, 5, 5, 1, 6, 5, 8, 2, 7, 6, 5, 8, 4, 8, 3, 5, 8, 8, 4, 5, 3, 1, 4, 2, 7, 7, 5, 6, 8, 7, 9, 0, 0, 2, 9, 0, 9, 5, 1, 7, 0, 2, 8, 3, 5, 2, 9, 7, 1, 6, 3, 4, 4, 5, 6, 2, 1, 2, 9, 6, 4, 0, 4, 3, 5, 2, 3, 1, 1, 7,
+        6, 0, 0, 6, 6, 5, 1, 0, 1, 2, 4, 1, 2, 0, 0, 6, 5, 9, 7, 5, 5, 8, 5, 1, 2, 7, 6, 1, 7, 8, 5, 8, 3, 8, 2, 9, 2, 0, 4, 1, 9, 7, 4, 8, 4, 4, 2, 3, 6, 0, 8, 0, 0, 7, 1, 9, 3, 0, 4, 5, 7, 6, 1, 8, 9, 3, 2, 3, 4, 9,
+        2, 2, 9, 2, 7, 9, 6, 5, 0, 1, 9, 8, 7, 5, 1, 8, 7, 2, 1, 2, 7, 2, 6, 7, 5, 0, 7, 9, 8, 1, 2, 5, 5, 4, 7, 0, 9, 5, 8, 9, 0, 4, 5, 5, 6, 3, 5, 7, 9, 2, 1, 2, 2, 1, 0, 3, 3, 3, 4, 6, 6, 9, 7, 4, 9, 9, 2, 3, 5, 6,
+        3, 0, 2, 5, 4, 9, 4, 7, 8, 0, 2, 4, 9, 0, 1, 1, 4, 1, 9, 5, 2, 1, 2, 3, 8, 2, 8, 1, 5, 3, 0, 9, 1, 1, 4, 0, 7, 9, 0, 7, 3, 8, 6, 0, 2, 5, 1, 5, 2, 2, 7, 4, 2, 9, 9, 5, 8, 1, 8, 0, 7, 2, 4, 7, 1, 6, 2, 5, 9, 1,
+        6, 6, 8, 5, 4, 5, 1, 3, 3, 3, 1, 2, 3, 9, 4, 8, 0, 4, 9, 4, 7, 0, 7, 9, 1, 1, 9, 1, 5, 3, 2, 6, 7, 3, 4, 3, 0, 2, 8, 2, 4, 4, 1, 8, 6, 0, 4, 1, 4, 2, 6, 3, 6, 3, 9, 5, 4, 8, 0, 0, 0, 4, 4, 8, 0, 0, 2, 6, 7, 0,
+        4, 9, 6, 2, 4, 8, 2, 0, 1, 7, 9, 2, 8, 9, 6, 4, 7, 6, 6, 9, 7, 5, 8, 3, 1, 8, 3, 2, 7, 1, 3, 1, 4, 2, 5, 1, 7, 0, 2, 9, 6, 9, 2, 3, 4, 8, 8, 9, 6, 2, 7, 6, 6, 8, 4, 4, 0, 3, 2, 3, 2, 6, 0, 9, 2, 7, 5, 2, 4, 9,
+        6, 0, 3, 5, 7, 9, 9, 6, 4, 6, 9, 2, 5, 6, 5, 0, 4, 9, 3, 6, 8, 1, 8, 3, 6, 0, 9, 0, 0, 3, 2, 3, 8, 0, 9, 2, 9, 3, 4, 5,
+        9, 5, 8, 8, 9, 7, 0, 6, 9, 5, 3, 6, 5, 3, 4, 9, 4, 0, 6, 0, 3, 4, 0, 2, 1, 6, 6, 5, 4, 4, 3, 7, 5, 5, 8, 9, 0, 0, 4, 5, 6, 3, 2, 8, 8, 2, 2, 5, 0, 5, 4, 5, 2, 5, 5, 6, 4, 0, 5, 6, 4, 4, 8, 2, 4, 6, 5, 1, 5, 1,
+        8, 7, 5, 4, 7, 1, 1, 9, 6, 2, 1, 8, 4, 4, 3, 9, 6, 5, 8, 2, 5, 3, 3, 7, 5, 4, 3, 8, 8, 5, 6, 9, 0, 9, 4, 1, 1, 3, 0, 3, 1, 5, 0, 9, 5, 2, 6, 1, 7, 9, 3, 7, 8, 0, 0, 2, 9, 7, 4, 1, 2, 0, 7, 6, 6, 5, 1, 4, 7, 9,
+        3, 9, 4, 2, 5, 9, 0, 2, 9, 8, 9, 6, 9, 5, 9, 4, 6, 9, 9, 5, 5, 6, 5, 7, 6, 1, 2, 1, 8, 6, 5, 6, 1, 9, 6, 7, 3, 3, 7, 8, 6, 2, 3, 6, 2, 5, 6, 1, 2, 5, 2, 1, 6, 3, 2, 0, 8, 6, 2, 8, 6, 9, 2, 2, 2, 1, 0, 3, 2, 7,
+        4, 8, 8, 9, 2, 1, 8, 6, 5, 4, 3, 6, 4, 8, 0, 2, 2, 9, 6, 7, 8, 0, 7, 0, 5, 7, 6, 5, 6, 1, 5, 1, 4, 4, 6, 3, 2, 0, 4, 6, 9, 2, 7, 9, 0, 6, 8, 2, 1, 2, 0, 7, 3, 8, 8, 3, 7, 7, 8, 1, 4, 2, 3, 3, 5, 6, 2, 8, 2, 3,
+        6, 0, 8, 9, 6, 3, 2, 0, 8, 0, 6, 8, 2, 2, 2, 4, 6, 8, 0, 1, 2, 2, 4, 8, 2, 6, 1, 1, 7, 7, 1, 8, 5, 8, 9, 6, 3, 8, 1, 4, 0, 9, 1, 8, 3, 9, 0, 3, 6, 7, 3, 6, 7, 2, 2, 2, 0, 8, 8, 8, 3, 2, 1, 5, 1, 3, 7, 5, 5, 6,
+        0, 0, 3, 7, 2, 7, 9, 8, 3, 9, 4, 0, 0, 4, 1, 5, 2, 9, 7, 0, 0, 2, 8, 7, 8, 3, 0, 7, 6, 6, 7, 0, 9, 4, 4, 4, 7, 4, 5, 6, 0, 1, 3, 4, 5, 5, 6, 4, 1, 7, 2, 5, 4, 3, 7, 0, 9, 0, 6, 9, 7, 9, 3, 9, 6, 1, 2, 2, 5, 7,
+        1, 4, 2, 9, 8, 9, 4, 6, 7, 1, 5, 4, 3, 5, 7, 8, 4, 6, 8, 7, 8, 8, 6, 1, 4, 4, 4, 5, 8, 1, 2, 3, 1, 4, 5, 9, 3, 5, 7, 1, 9, 8, 4, 9, 2, 2, 5, 2, 8, 4, 7, 1, 6, 0, 5, 0, 4, 9, 2, 2, 1, 2, 4, 2, 4, 7, 0, 1, 4, 1,
+        2, 1, 4, 7, 8, 0, 5, 7, 3, 4, 5, 5, 1, 0, 5, 0, 0, 8, 0, 1, 9, 0, 8, 6, 9, 9, 6, 0, 3, 3, 0, 2, 7, 6, 3, 4, 7, 8, 7, 0, 8, 1, 0, 8, 1, 7, 5, 4, 5, 0, 1, 1, 9, 3, 0, 7, 1, 4, 1, 2, 2, 3, 3, 9, 0, 8, 6, 6, 3, 9,
+        3, 8, 3, 3, 9, 5, 2, 9, 4, 2, 5, 7, 8, 6, 9, 0, 5, 0, 7, 6, 4, 3, 1, 0, 0, 6, 3, 8, 3, 5, 1, 9, 8, 3, 4, 3, 8, 9, 3, 4, 1, 5, 9, 6, 1, 3, 1, 8, 5, 4, 3, 4, 7, 5, 4, 6, 4, 9, 5, 5, 6, 9, 7, 8, 1, 0, 3, 8, 2, 9,
+        3, 0, 9, 7, 1, 6, 4, 6, 5, 1, 4, 3, 8, 4, 0, 7, 0, 0, 7, 0, 7, 3, 6, 0, 4, 1, 1, 2, 3, 7, 3, 5, 9, 9, 8, 4, 3, 4, 5, 2, 2, 5, 1, 6, 1, 0, 5, 0, 7, 0, 2, 7, 0, 5, 6, 2, 3, 5, 2, 6, 6, 0, 1, 2, 7, 6, 4, 8, 4, 8,
+        3, 0, 8, 4, 0, 7, 6, 1, 1, 8, 3, 0, 1, 3, 0, 5, 2, 7, 9, 3, 2, 0, 5, 4, 2, 7, 4, 6, 2, 8, 6, 5, 4, 0, 3, 6, 0, 3, 6, 7, 4, 5, 3, 2, 8, 6, 5, 1, 0, 5, 7, 0, 6, 5, 8, 7, 4, 8, 8, 2, 2, 5, 6, 9, 8, 1, 5, 7, 9, 3,
+        6, 7, 8, 9, 7, 6, 6, 9, 7, 4, 2, 2, 0, 5, 7, 5, 0, 5, 9, 6, 8, 3, 4, 4, 0, 8, 6, 9, 7, 3, 5, 0, 2, 0, 1, 4, 1, 0, 2, 0, 6, 7, 2, 3, 5, 8, 5, 0, 2, 0, 0, 7, 2, 4, 5, 2, 2, 5, 6, 3, 2, 6, 5, 1, 3, 4, 1, 0, 5, 5,
+        9, 2, 4, 0, 1, 9, 0, 2, 7, 4, 2, 1, 6, 2, 4, 8, 4, 3, 9, 1, 4, 0, 3, 5, 9, 9, 8, 9, 5, 3, 5, 3, 9, 4, 5, 9, 0, 9, 4, 4, 0, 7, 0, 4, 6, 9, 1, 2, 0, 9, 1, 4, 0, 9, 3, 8, 7, 0, 0, 1, 2, 6, 4, 5, 6, 0, 0, 1, 6, 2,
+        3, 7, 4, 2, 8, 8, 0, 2, 1, 0, 9, 2, 7, 6, 4, 5, 7, 9, 3, 1, 0, 6, 5, 7, 9, 2, 2, 9, 5, 5, 2, 4, 9, 8, 8, 7, 2, 7, 5, 8, 4, 6, 1, 0, 1, 2, 6, 4, 8, 3, 6, 9, 9, 9, 8, 9, 2, 2, 5, 6, 9, 5, 9, 6, 8, 8, 1, 5, 9, 2,
+        0, 5, 6, 0, 0, 1, 0, 1, 6, 5, 5, 2, 5, 6, 3, 7, 5, 6, 7, 8
+    };
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java
new file mode 100644
index 0000000..155a247
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.os;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.MediumTest;
+import junit.framework.TestCase;
+
+public class MessageQueueTest extends TestCase {
+
+    private static class BaseTestHandler extends TestHandlerThread {
+        Handler mHandler;
+        int mLastMessage;
+        int mCount;
+
+        public BaseTestHandler() {
+        }
+
+        public void go() {
+            mHandler = new Handler() {
+                public void handleMessage(Message msg) {
+                    BaseTestHandler.this.handleMessage(msg);
+                }
+            };
+        }
+
+        public void handleMessage(Message msg) {
+            if (mCount <= mLastMessage) {
+                if (msg.what != mCount) {
+                    failure(new RuntimeException(
+                            "Expected message #" + mCount
+                                    + ", received #" + msg.what));
+                } else if (mCount == mLastMessage) {
+                    success();
+                }
+                mCount++;
+            } else {
+                failure(new RuntimeException(
+                        "Message received after done, #" + msg.what));
+            }
+        }
+    }
+
+    @MediumTest
+    public void testMessageOrder() throws Exception {
+        TestHandlerThread tester = new BaseTestHandler() {
+            public void go() {
+                super.go();
+                long now = SystemClock.uptimeMillis() + 200;
+                mLastMessage = 4;
+                mCount = 0;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(2), now + 1);
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now + 2);
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(4), now + 2);
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(0), now + 0);
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(1), now + 0);
+            }
+        };
+
+        tester.doTest(1000);
+    }
+
+    @MediumTest
+    public void testAtFrontOfQueue() throws Exception {
+        TestHandlerThread tester = new BaseTestHandler() {
+            public void go() {
+                super.go();
+                long now = SystemClock.uptimeMillis() + 200;
+                mLastMessage = 3;
+                mCount = 0;
+                mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now);
+                mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(2));
+                mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(0));
+            }
+
+            public void handleMessage(Message msg) {
+                super.handleMessage(msg);
+                if (msg.what == 0) {
+                    mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(1));
+                }
+            }
+        };
+
+        tester.doTest(1000);
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java
new file mode 100644
index 0000000..9228a43f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+
+public class MessengerService extends Service {
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            Message reply = Message.obtain();
+            reply.copyFrom(msg);
+            try {
+                msg.replyTo.send(reply);
+            } catch (RemoteException e) {
+            }
+        }
+    };
+    
+    private final Messenger mMessenger = new Messenger(mHandler);
+    
+    public MessengerService() {
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mMessenger.getBinder();
+    }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java
new file mode 100644
index 0000000..2a3e204d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.os;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class MessengerTest extends AndroidTestCase {
+    private Messenger mServiceMessenger;
+    
+    private ServiceConnection mConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (MessengerTest.this) {
+                mServiceMessenger = new Messenger(service);
+                MessengerTest.this.notifyAll();
+            }
+        }
+        public void onServiceDisconnected(ComponentName name) {
+            mServiceMessenger = null;
+        }
+    };
+    
+    private class TestThread extends TestHandlerThread {
+        private Handler mTestHandler;
+        private Messenger mTestMessenger;
+        
+        public void go() {
+            synchronized (MessengerTest.this) {
+                mTestHandler = new Handler() {
+                    public void handleMessage(Message msg) {
+                        TestThread.this.handleMessage(msg);
+                    }
+                };
+                mTestMessenger = new Messenger(mTestHandler);
+                TestThread.this.executeTest();
+            }
+        }
+
+        public void executeTest() {
+            Message msg = Message.obtain();
+            msg.arg1 = 100;
+            msg.arg2 = 1000;
+            msg.replyTo = mTestMessenger;
+            try {
+                mServiceMessenger.send(msg);
+            } catch (RemoteException e) {
+            }
+        }
+        
+        public void handleMessage(Message msg) {
+            if (msg.arg1 != 100) {
+                failure(new RuntimeException(
+                        "Message.arg1 is not 100: " + msg.arg1));
+                return;
+            }
+            if (msg.arg2 != 1000) {
+                failure(new RuntimeException(
+                        "Message.arg2 is not 1000: " + msg.arg2));
+                return;
+            }
+            if (!mTestMessenger.equals(msg.replyTo)) {
+                failure(new RuntimeException(
+                        "Message.replyTo is not me: " + msg.replyTo));
+                return;
+            }
+            success();
+        }
+    };
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        getContext().bindService(new Intent(mContext, MessengerService.class),
+                mConnection, Context.BIND_AUTO_CREATE);
+        synchronized (this) {
+            while (mServiceMessenger == null) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        getContext().unbindService(mConnection);
+    }
+
+    @MediumTest
+    public void testSend() {
+        (new TestThread()).doTest(1000);
+        
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java b/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java
new file mode 100644
index 0000000..bf02509
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import com.google.android.collect.Lists;
+import junit.framework.TestSuite;
+
+import java.util.Enumeration;
+import java.util.List;
+
+public class OsTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(OsTests.class.getName());
+
+        suite.addTestSuite(AidlTest.class);
+        suite.addTestSuite(BroadcasterTest.class);
+        suite.addTestSuite(FileObserverTest.class);
+        suite.addTestSuite(IdleHandlerTest.class);
+        suite.addTestSuite(MemoryFileTest.class);
+        suite.addTestSuite(MessageQueueTest.class);
+        suite.addTestSuite(MessengerTest.class);
+        suite.addTestSuite(PowerManagerTest.class);
+        suite.addTestSuite(SystemPropertiesTest.class);
+
+        return suite;
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java
new file mode 100644
index 0000000..bd5c955
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2008 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.unit_tests.os;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class PowerManagerTest extends AndroidTestCase {
+    
+    private PowerManager mPm;
+    
+    /**
+     * Setup any common data for the upcoming tests.
+     */
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+    }
+    
+    /**
+     * Confirm that the setup is good.
+     * 
+     * @throws Exception
+     */
+    @MediumTest
+    public void testPreconditions() throws Exception {
+        assertNotNull(mPm);
+    }
+
+    /**
+     * Confirm that we can create functional wakelocks.
+     * 
+     * @throws Exception
+     */
+    @MediumTest
+    public void testNewWakeLock() throws Exception {
+        PowerManager.WakeLock wl = mPm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "FULL_WAKE_LOCK");
+        doTestWakeLock(wl);
+
+        wl = mPm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "SCREEN_BRIGHT_WAKE_LOCK");
+        doTestWakeLock(wl);
+
+        wl = mPm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "SCREEN_DIM_WAKE_LOCK");
+        doTestWakeLock(wl);
+
+        wl = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK");
+        doTestWakeLock(wl);
+        
+        // TODO: Some sort of functional test (maybe not in the unit test here?) 
+        // that confirms that things are really happening e.g. screen power, keyboard power.
+}
+    
+    /**
+     * Confirm that we can't create dysfunctional wakelocks.
+     * 
+     * @throws Exception
+     */
+    @MediumTest
+    public void testBadNewWakeLock() throws Exception {
+        
+        final int badFlags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK 
+                            | PowerManager.SCREEN_DIM_WAKE_LOCK;
+        // wrap in try because we want the error here
+        try {
+            PowerManager.WakeLock wl = mPm.newWakeLock(badFlags, "foo");
+        } catch (IllegalArgumentException e) {
+            return;
+        }
+        fail("Bad WakeLock flag was not caught.");
+    }
+    
+    /**
+     * Apply a few tests to a wakelock to make sure it's healthy.
+     * 
+     * @param wl The wakelock to be tested.
+     */
+    private void doTestWakeLock(PowerManager.WakeLock wl) {
+        // First try simple acquire/release
+        wl.acquire();
+        assertTrue(wl.isHeld());
+        wl.release();
+        assertFalse(wl.isHeld());
+        
+        // Try ref-counted acquire/release
+        wl.setReferenceCounted(true);
+        wl.acquire();
+        assertTrue(wl.isHeld());
+        wl.acquire();
+        assertTrue(wl.isHeld());
+        wl.release();
+        assertTrue(wl.isHeld());
+        wl.release();
+        assertFalse(wl.isHeld());
+        
+        // Try non-ref-counted
+        wl.setReferenceCounted(false);
+        wl.acquire();
+        assertTrue(wl.isHeld());
+        wl.acquire();
+        assertTrue(wl.isHeld());
+        wl.release();
+        assertFalse(wl.isHeld());
+        
+        // TODO: Threaded test (needs handler) to make sure timed wakelocks work too
+    }
+    
+    
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java
new file mode 100644
index 0000000..df08bb9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import static junit.framework.Assert.assertEquals;
+import junit.framework.TestCase;
+
+import android.os.SystemProperties;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class SystemPropertiesTest extends TestCase {
+    private static final String KEY = "com.android.unit_tests";
+    @SmallTest
+    public void testProperties() throws Exception {
+        if (false) {
+        String value;
+       
+        SystemProperties.set(KEY, "");
+        value = SystemProperties.get(KEY, "default");
+        assertEquals("default", value);
+
+        SystemProperties.set(KEY, "AAA");
+        value = SystemProperties.get(KEY, "default");
+        assertEquals("AAA", value);
+
+        value = SystemProperties.get(KEY);
+        assertEquals("AAA", value);
+
+        SystemProperties.set(KEY, "");
+        value = SystemProperties.get(KEY, "default");
+        assertEquals("default", value);
+
+        value = SystemProperties.get(KEY);
+        assertEquals("", value);
+        }
+    }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java b/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java
new file mode 100644
index 0000000..dba8dde
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 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.unit_tests.os;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue.IdleHandler;
+
+abstract class TestHandlerThread {
+    private boolean mDone = false;
+    private boolean mSuccess = false;
+    private RuntimeException mFailure = null;
+    private Looper mLooper;
+    
+    public abstract void go();
+
+    public TestHandlerThread() {
+    }
+
+    public void doTest(long timeout) {
+        (new LooperThread()).start();
+
+        synchronized (this) {
+            long now = System.currentTimeMillis();
+            long endTime = now + timeout;
+            while (!mDone && now < endTime) {
+                try {
+                    wait(endTime-now);
+                }
+                catch (InterruptedException e) {
+                }
+                now = System.currentTimeMillis();
+            }
+        }
+
+        mLooper.quit();
+
+        if (!mDone) {
+            throw new RuntimeException("test timed out");
+        }
+        if (!mSuccess) {
+            throw mFailure;
+        }
+    }
+
+    public Looper getLooper() {
+        return mLooper;
+    }
+
+    public void success() {
+        synchronized (this) {
+            mSuccess = true;
+            quit();
+        }
+    }
+
+    public void failure(RuntimeException failure) {
+        synchronized (this) {
+            mSuccess = false;
+            mFailure = failure;
+            quit();
+        }
+    }
+
+    class LooperThread extends Thread {
+        public void run() {
+            Looper.prepare();
+            mLooper = Looper.myLooper();
+            go();
+            Looper.loop();
+
+            synchronized (TestHandlerThread.this) {
+                mDone = true;
+                if (!mSuccess && mFailure == null) {
+                    mFailure = new RuntimeException("no failure exception set");
+                }
+                TestHandlerThread.this.notifyAll();
+            }
+        }
+
+    }
+
+    private void quit() {
+        synchronized (this) {
+            mDone = true;
+            notifyAll();
+        }
+    }
+}
diff --git a/tests/CoreTests/Android.mk b/tests/CoreTests/Android.mk
new file mode 100644
index 0000000..8338432
--- /dev/null
+++ b/tests/CoreTests/Android.mk
@@ -0,0 +1,2 @@
+include $(call all-subdir-makefiles)
+
diff --git a/tests/CoreTests/MODULE_LICENSE_APACHE2 b/tests/CoreTests/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/CoreTests/MODULE_LICENSE_APACHE2
diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk
new file mode 100644
index 0000000..e6b5c45
--- /dev/null
+++ b/tests/CoreTests/android/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+	$(call all-subdir-java-files)
+LOCAL_SRC_FILES += \
+	$(call all-java-files-under, ../com)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := CoreTests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml
new file mode 100644
index 0000000..4809f844
--- /dev/null
+++ b/tests/CoreTests/android/AndroidManifest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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="android.core">
+    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+    <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+
+    <!-- location test permissions -->
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
+    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="StubTestBrowserActivity" android:label="Stubbed Test Browser">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.FOR_TESTS_ONLY"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.test.TestBrowserTests" android:label="Test Browser Tests">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.UNIT_TEST"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation
+    	android:name="android.test.InstrumentationTestRunner"
+    	android:targetPackage="android.core"
+    	android:label="Core Tests" />
+</manifest>
diff --git a/tests/CoreTests/android/content/ObserverNodeTest.java b/tests/CoreTests/android/content/ObserverNodeTest.java
new file mode 100644
index 0000000..68cc75b
--- /dev/null
+++ b/tests/CoreTests/android/content/ObserverNodeTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 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.content;
+
+import java.util.ArrayList;
+
+import android.content.ContentService.ObserverCall;
+import android.content.ContentService.ObserverNode;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class ObserverNodeTest extends AndroidTestCase {   
+    static class TestObserver  extends ContentObserver {
+        public TestObserver() {
+            super(new Handler());
+        }
+    }
+    
+    public void testUri() {
+        ObserverNode root = new ObserverNode("");
+        Uri[] uris = new Uri[] {
+            Uri.parse("content://c/a/"),
+            Uri.parse("content://c/"),
+            Uri.parse("content://x/"), 
+            Uri.parse("content://c/b/"),
+            Uri.parse("content://c/a/a1/1/"),
+            Uri.parse("content://c/a/a1/2/"),
+            Uri.parse("content://c/b/1/"),
+            Uri.parse("content://c/b/2/"),
+        };
+        
+        int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3};
+        
+        // special case
+        root.addObserver(uris[0], new TestObserver().getContentObserver(), false);
+        for(int i = 1; i < uris.length; i++) {
+            root.addObserver(uris[i], new TestObserver().getContentObserver(), true);
+        }
+        
+        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
+        
+        for (int i = nums.length - 1; i >=0; --i) {
+            root.collectObservers(uris[i], 0, null, false, calls);
+            assertEquals(nums[i], calls.size());
+            calls.clear();
+        }
+    }
+    
+    public void testUriNotNotify() {
+        ObserverNode root = new ObserverNode("");
+        Uri[] uris = new Uri[] {
+            Uri.parse("content://c/"),
+            Uri.parse("content://x/"), 
+            Uri.parse("content://c/a/"),
+            Uri.parse("content://c/b/"),
+            Uri.parse("content://c/a/1/"),
+            Uri.parse("content://c/a/2/"),
+            Uri.parse("content://c/b/1/"),
+            Uri.parse("content://c/b/2/"),
+        };
+        int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1};
+        
+        for(int i = 0; i < uris.length; i++) {
+            root.addObserver(uris[i], new TestObserver().getContentObserver(), false);
+        }
+        
+        ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
+        
+        for (int i = uris.length - 1; i >=0; --i) {
+            root.collectObservers(uris[i], 0, null, false, calls);        
+            assertEquals(nums[i], calls.size());
+            calls.clear();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/tests/CoreTests/android/content/SyncStorageEngineTest.java
new file mode 100644
index 0000000..36805b1
--- /dev/null
+++ b/tests/CoreTests/android/content/SyncStorageEngineTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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.content;
+
+import android.test.AndroidTestCase;
+import android.test.RenamingDelegatingContext;
+import android.test.mock.MockContext;
+import android.test.mock.MockContentResolver;
+import android.provider.Sync;
+
+public class SyncStorageEngineTest extends AndroidTestCase {
+
+    /**
+     * Test that we handle the case of a history row being old enough to purge before the
+     * correcponding sync is finished. This can happen if the clock changes while we are syncing.
+     */
+    public void testPurgeActiveSync() throws Exception {
+        final String account = "a@example.com";
+        final String authority = "testprovider";
+
+        MockContentResolver mockResolver = new MockContentResolver();
+
+        SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
+                new TestContext(mockResolver, getContext()));
+
+        long time0 = 1000;
+        long historyId = engine.insertStartSyncEvent(
+                account, authority, time0, Sync.History.SOURCE_LOCAL);
+        long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
+        engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
+    }
+}
+
+class TestContext extends ContextWrapper {
+
+    ContentResolver mResolver;
+
+    public TestContext(ContentResolver resolver, Context realContext) {
+        super(new RenamingDelegatingContext(new MockContext(), realContext, "test."));
+        mResolver = resolver;
+    }
+
+    @Override
+    public void enforceCallingOrSelfPermission(String permission, String message) {
+    }
+
+
+    @Override
+    public ContentResolver getContentResolver() {
+        return mResolver;
+    }
+}
diff --git a/tests/CoreTests/android/core/AbstractJDBCDriverTest.java b/tests/CoreTests/android/core/AbstractJDBCDriverTest.java
new file mode 100644
index 0000000..e381a5e
--- /dev/null
+++ b/tests/CoreTests/android/core/AbstractJDBCDriverTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Tests for the most commonly used methods of sql like creating a connection,
+ * inserting, selecting, updating.
+ */
+public abstract class AbstractJDBCDriverTest extends TestCase {
+
+    @MediumTest
+    public void testJDBCDriver() throws Exception {
+        Connection firstConnection = null;
+        Connection secondConnection = null;
+        File dbFile = getDbFile();
+        String connectionURL = getConnectionURL();
+        Statement firstStmt = null;
+        Statement secondStmt = null;
+        try {
+            Class.forName(getJDBCDriverClassName());
+            firstConnection = DriverManager.getConnection(connectionURL);
+            secondConnection = DriverManager.getConnection(connectionURL);
+
+            String[] ones = {"hello!", "goodbye"};
+            short[] twos = {10, 20};
+            String[] onesUpdated = new String[ones.length];
+            for (int i = 0; i < ones.length; i++) {
+                onesUpdated[i] = ones[i] + twos[i];
+            }
+            firstStmt = firstConnection.createStatement();
+            firstStmt.execute("create table tbl1(one varchar(10), two smallint)");
+            secondStmt = secondConnection.createStatement();
+
+            autoCommitInsertSelectTest(firstStmt, ones, twos);
+            updateSelectCommitSelectTest(firstStmt, secondStmt, ones, onesUpdated, twos);
+            updateSelectRollbackSelectTest(firstStmt, secondStmt, onesUpdated, ones, twos);
+        } finally {
+            closeConnections(firstConnection, secondConnection, dbFile, firstStmt, secondStmt);
+        }
+    }
+
+    protected abstract String getJDBCDriverClassName();
+    protected abstract String getConnectionURL();
+    protected abstract File getDbFile();
+
+    private void closeConnections(Connection firstConnection, Connection secondConnection,
+            File dbFile, Statement firstStmt, Statement secondStmt) {
+        String failText = null;
+        try {
+            if (firstStmt != null) {
+                firstStmt.execute("drop table tbl1");
+            }
+        } catch (SQLException e) {
+            failText = e.getLocalizedMessage();
+        }
+        try {
+            if (firstStmt != null) {
+                firstStmt.close();
+            }
+        } catch (SQLException e) {
+            failText = e.getLocalizedMessage();
+        }
+        try {
+            if (firstConnection != null) {
+                firstConnection.close();
+            }
+        } catch (SQLException e) {
+            failText = e.getLocalizedMessage();
+        }
+        try {
+            if (secondStmt != null) {
+                secondStmt.close();
+            }
+        } catch (SQLException e) {
+            failText = e.getLocalizedMessage();
+        }
+        try {
+            if (secondConnection != null) {
+                secondConnection.close();
+            }
+        } catch (SQLException e) {
+            failText = e.getLocalizedMessage();
+        }
+        dbFile.delete();
+        assertNull(failText, failText);
+    }
+
+    /**
+     * Inserts the values from 'ones' with the values from 'twos' into 'tbl1'
+     * @param stmt the statement to use for the inserts.
+     * @param ones the string values to insert into tbl1.
+     * @param twos the corresponding numerical values to insert into tbl1.
+     * @throws SQLException in case of a problem during insert.
+     */
+    private void autoCommitInsertSelectTest(Statement stmt, String[] ones,
+            short[] twos) throws SQLException {
+        for (int i = 0; i < ones.length; i++) {
+            stmt.execute("insert into tbl1 values('" + ones[i] + "'," + twos[i]
+                    + ")");
+        }
+        assertAllFromTbl1(stmt, ones, twos);
+    }
+
+    /**
+     * Asserts that all values that where added to tbl1 are actually in tbl1.
+     * @param stmt the statement to use for the select.
+     * @param ones the string values that where added.
+     * @param twos the numerical values that where added.
+     * @throws SQLException in case of a problem during select.
+     */
+    private void assertAllFromTbl1(Statement stmt, String[] ones, short[] twos)
+            throws SQLException {
+        ResultSet rs = stmt.executeQuery("select * from tbl1");
+        int i = 0;
+        for (; rs.next(); i++) {
+            assertTrue(i < ones.length);
+            assertEquals(ones[i], rs.getString("one"));
+            assertEquals(twos[i], rs.getShort("two"));
+        }
+        assertEquals(i, ones.length);
+    }
+
+    /**
+     * Tests the results of an update followed bz a select on a diffrent statement.
+     * After that the first statement commits its update. and now the second 
+     * statement should also be able to see the changed values in a select.
+     * @param firstStmt the statement to use for the update and commit.
+     * @param secondStmt the statement that should be used to check if the commit works
+     * @param ones the original string values.
+     * @param onesUpdated the updated string values.
+     * @param twos the numerical values.
+     * @throws SQLException in case of a problem during any of the executed commands.
+     */
+    private void updateSelectCommitSelectTest(Statement firstStmt,
+            Statement secondStmt, String[] ones, String[] onesUpdated,
+            short[] twos) throws SQLException {
+        firstStmt.getConnection().setAutoCommit(false);
+        try {
+            updateOnes(firstStmt, onesUpdated, twos);
+            assertAllFromTbl1(secondStmt, ones, twos);
+            firstStmt.getConnection().commit();
+            assertAllFromTbl1(secondStmt, onesUpdated, twos);
+        } finally {
+            firstStmt.getConnection().setAutoCommit(true);
+        }
+    }
+
+    /**
+     * Tests if an update followed by a select works. After that a rollback will 
+     * be made and again a select should show that the rollback worked. 
+     * @param firstStmt the statement to use for the update and the rollback
+     * @param secondStmt the statement to use for checking if the rollback worked as intended.
+     * @param ones the original string values.
+     * @param onesUpdated the updated string values.
+     * @param twos the nomerical values.
+     * @throws SQLException in case of a problem during any command.
+     */
+    private void updateSelectRollbackSelectTest(Statement firstStmt,
+            Statement secondStmt, String[] ones, String[] onesUpdated,
+            short[] twos) throws SQLException {
+        firstStmt.getConnection().setAutoCommit(false);
+        try {
+            updateOnes(firstStmt, onesUpdated, twos);
+            assertAllFromTbl1(secondStmt, ones, twos);
+            firstStmt.getConnection().rollback();
+            assertAllFromTbl1(secondStmt, ones, twos);
+        } finally {
+            firstStmt.getConnection().setAutoCommit(true);
+        }
+    }
+
+    /**
+     * updates the sring values. the original values are stored in 'ones'
+     * and the updated values in 'ones_updated'
+     * @param stmt the statement to use for the update.
+     * @param onesUpdated the new string values.
+     * @param twos the numerical values.
+     * @throws SQLException in case of a problem during update.
+     */
+    private void updateOnes(Statement stmt, String[] onesUpdated, short[] twos)
+            throws SQLException {
+        for (int i = 0; i < onesUpdated.length; i++) {
+            stmt.execute("UPDATE tbl1 SET one = '" + onesUpdated[i]
+                    + "' WHERE two = " + twos[i]);
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/ArrayListTest.java b/tests/CoreTests/android/core/ArrayListTest.java
new file mode 100644
index 0000000..763bf99
--- /dev/null
+++ b/tests/CoreTests/android/core/ArrayListTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * This test case tests several often used functionality of ArrayLists.
+ */
+public class ArrayListTest extends TestCase {
+
+    @SuppressWarnings("unchecked")
+    @SmallTest
+    public void testArrayList() throws Exception {
+        ArrayList array = new ArrayList();
+        assertEquals(0, array.size());
+        assertTrue(array.isEmpty());
+
+        array.add(new Integer(0));
+        array.add(0, new Integer(1));
+        array.add(1, new Integer(2));
+        array.add(new Integer(3));
+        array.add(new Integer(1));
+
+        assertEquals(5, array.size());
+        assertFalse(array.isEmpty());
+
+        assertEquals(1, ((Integer) array.get(0)).intValue());
+        assertEquals(2, ((Integer) array.get(1)).intValue());
+        assertEquals(0, ((Integer) array.get(2)).intValue());
+        assertEquals(3, ((Integer) array.get(3)).intValue());
+        assertEquals(1, ((Integer) array.get(4)).intValue());
+
+        assertFalse(array.contains(null));
+        assertTrue(array.contains(new Integer(2)));
+        assertEquals(0, array.indexOf(new Integer(1)));
+        assertEquals(4, array.lastIndexOf(new Integer(1)));
+        assertTrue(array.indexOf(new Integer(5)) < 0);
+        assertTrue(array.lastIndexOf(new Integer(5)) < 0);
+
+
+        array.remove(1);
+        array.remove(1);
+
+        assertEquals(3, array.size());
+        assertFalse(array.isEmpty());
+        assertEquals(1, ((Integer) array.get(0)).intValue());
+        assertEquals(3, ((Integer) array.get(1)).intValue());
+        assertEquals(1, ((Integer) array.get(2)).intValue());
+
+        assertFalse(array.contains(null));
+        assertFalse(array.contains(new Integer(2)));
+        assertEquals(0, array.indexOf(new Integer(1)));
+        assertEquals(2, array.lastIndexOf(new Integer(1)));
+        assertTrue(array.indexOf(new Integer(5)) < 0);
+        assertTrue(array.lastIndexOf(new Integer(5)) < 0);
+
+        array.clear();
+
+        assertEquals(0, array.size());
+        assertTrue(array.isEmpty());
+        assertTrue(array.indexOf(new Integer(5)) < 0);
+        assertTrue(array.lastIndexOf(new Integer(5)) < 0);
+
+        ArrayList al = new ArrayList();
+
+        assertFalse(al.remove(null));
+        assertFalse(al.remove("string"));
+
+        al.add("string");
+        al.add(null);
+
+        assertTrue(al.remove(null));
+        assertTrue(al.remove("string"));
+    }
+}
+
diff --git a/tests/CoreTests/android/core/AtParserTest.java b/tests/CoreTests/android/core/AtParserTest.java
new file mode 100644
index 0000000..09cb6e9
--- /dev/null
+++ b/tests/CoreTests/android/core/AtParserTest.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+import android.bluetooth.AtCommandHandler;
+import android.bluetooth.AtCommandResult;
+import android.bluetooth.AtParser;
+
+import java.util.*;
+import junit.framework.*;
+
+public class AtParserTest extends TestCase {
+
+    /* An AtCommandHandler instrumented for testing purposes
+     */
+    private class HandlerTest extends AtCommandHandler {
+        boolean mBasicCalled, mActionCalled, mReadCalled, mTestCalled, 
+                mSetCalled;
+        int mBasicReturn, mActionReturn, mReadReturn, mTestReturn, mSetReturn;
+        Object[] mSetArgs;
+        String mBasicArgs;
+
+        HandlerTest() {
+            this(AtCommandResult.ERROR, AtCommandResult.ERROR,
+                 AtCommandResult.ERROR, AtCommandResult.ERROR,
+                 AtCommandResult.ERROR);
+        }
+
+        HandlerTest(int a, int b, int c, int d, int e) {
+            mBasicReturn = a;
+            mActionReturn = b;
+            mReadReturn = c;
+            mSetReturn = d;
+            mTestReturn = e;
+            reset();
+        }
+        public void reset() {
+            mBasicCalled = false;
+            mActionCalled = false;
+            mReadCalled = false;
+            mSetCalled = false;
+            mTestCalled = false;
+            mSetArgs = null;
+            mBasicArgs = null;
+        }
+        public boolean wasCalled() {   // helper
+            return mBasicCalled || mActionCalled || mReadCalled ||
+                    mTestCalled || mSetCalled;
+        }
+        @Override
+        public AtCommandResult handleBasicCommand(String args) {
+            mBasicCalled = true;
+            mBasicArgs = args;
+            return new AtCommandResult(mBasicReturn);
+        }
+        @Override
+        public AtCommandResult handleActionCommand() {
+            mActionCalled = true;
+            return new AtCommandResult(mActionReturn);
+        }
+        @Override
+        public AtCommandResult handleReadCommand() {
+            mReadCalled = true;
+            return new AtCommandResult(mReadReturn);
+        }
+        @Override
+        public AtCommandResult handleSetCommand(Object[] args) {
+            mSetCalled = true;
+            mSetArgs = args;
+            return new AtCommandResult(mSetReturn);
+        }
+        @Override
+        public AtCommandResult handleTestCommand() {
+            mTestCalled = true;
+            return new AtCommandResult(mTestReturn);
+        }
+    }
+
+    private AtParser mParser;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mParser = new AtParser();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+
+    /* Test that the right method is being called
+     */
+/*    public void testBasic1() throws Exception {
+        HandlerTest D = new HandlerTest(0, 1, 1, 1, 1);
+        HandlerTest A = new HandlerTest(0, 1, 1, 1, 1);
+        mParser.register('D', D);
+        mParser.register('A', A);
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("  A T D = ? T 1 2 3  4   ").toStrings()));
+        assertTrue(D.mBasicCalled);
+        assertFalse(D.mActionCalled);
+        assertFalse(D.mTestCalled);
+        assertFalse(D.mSetCalled);
+        assertFalse(D.mReadCalled);
+        assertFalse(A.wasCalled());
+        assertEquals("=?T1234", D.mBasicArgs);
+    }
+*/
+    /* Test some crazy strings
+     *//*
+    public void testBasic2() throws Exception {
+        HandlerTest A = new HandlerTest(0, 1, 1, 1, 1);
+        mParser.register('A', A);
+
+        assertTrue(Arrays.equals(
+                   new String[]{},
+                   mParser.process("     ").toStrings()));
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("  a T a t \"\"  1 2 3 a 4   ")
+                           .toStrings()));
+        assertEquals("T\"\"123A4", A.mBasicArgs);
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("  a T a t  \"foo BaR12Z\" 1 2 3 a 4   ")
+                           .toStrings()));
+        assertEquals("T\"foo BaR12Z\"123A4", A.mBasicArgs);
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("ATA\"").toStrings()));
+        assertEquals("\"\"", A.mBasicArgs);
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("ATA\"a").toStrings()));
+        assertEquals("\"a\"", A.mBasicArgs);
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("ATa\" ").toStrings()));
+        assertEquals("\" \"", A.mBasicArgs);
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("ATA  \"one \" two \"t hr ee ")
+                           .toStrings()));
+        assertEquals("\"one \"TWO\"t hr ee \"", A.mBasicArgs);
+    }*/
+
+    /* Simple extended commands
+     *//*
+    public void testExt1() throws Exception {
+        HandlerTest A = new HandlerTest(1, 0, 0, 0, 0);
+        mParser.register("+A", A);
+
+        assertTrue(Arrays.equals(
+                   new String[]{"ERROR"},
+                   mParser.process("AT+B").toStrings()));
+        assertFalse(A.wasCalled());
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+A").toStrings()));
+        assertTrue(A.mActionCalled);
+        A.mActionCalled = false;
+        assertFalse(A.wasCalled());
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+A=").toStrings()));
+        assertTrue(A.mSetCalled);
+        A.mSetCalled = false;
+        assertFalse(A.wasCalled());
+        assertEquals(1, A.mSetArgs.length);
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+A=?").toStrings()));
+        assertTrue(A.mTestCalled);
+        A.mTestCalled = false;
+        assertFalse(A.wasCalled());
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+A?").toStrings()));
+        assertTrue(A.mReadCalled);
+        A.mReadCalled = false;
+        assertFalse(A.wasCalled());
+        A.reset();
+    }
+*/
+
+
+    /* Test chained commands
+     *//*
+    public void testChain1() throws Exception {
+        HandlerTest A = new HandlerTest(0, 1, 1, 1, 1);
+        HandlerTest B = new HandlerTest(1, 0, 0, 0, 0);
+        HandlerTest C = new HandlerTest(1, 1, 1, 1, 1);
+        mParser.register('A', A);
+        mParser.register("+B", B);
+        mParser.register("+C", C);
+
+        assertTrue(Arrays.equals(
+                   new String[]{"ERROR"},
+                   mParser.process("AT+B;+C").toStrings()));
+        assertTrue(B.mActionCalled);
+        assertTrue(C.mActionCalled);
+        B.reset();
+        C.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"ERROR"},
+                   mParser.process("AT+C;+B").toStrings()));
+        assertFalse(B.wasCalled());
+        assertTrue(C.mActionCalled);
+        B.reset();
+        C.reset();
+    }*/
+
+    /* Test Set command
+     *//*
+    public void testSet1() throws Exception {
+        HandlerTest A = new HandlerTest(1, 1, 1, 0, 1);
+        mParser.register("+AAAA", A);
+        Object[] expectedResult;
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+AAAA=1").toStrings()));
+        expectedResult = new Object[]{(Integer)1};
+        assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+AAAA=1,2,3").toStrings()));
+        expectedResult = new Object[]{(Integer)1, (Integer)2, (Integer)3};
+        assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+AAAA=3,0,0,1").toStrings()));
+        expectedResult = new Object[]{(Integer)3, (Integer)0, (Integer)0,
+                                      (Integer)1};
+        assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+AAAA=\"foo\",1,\"b,ar").toStrings()));
+        expectedResult = new Object[]{"\"foo\"", 1, "\"b,ar\""};
+        assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+AAAA=").toStrings()));
+        expectedResult = new Object[]{""};
+        assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+AAAA=,").toStrings()));
+        expectedResult = new Object[]{"", ""};
+        assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+AAAA=,,,").toStrings()));
+        expectedResult = new Object[]{"", "", "", ""};
+        assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("AT+AAAA=,1,,\"foo\",").toStrings()));
+        expectedResult = new Object[]{"", 1, "", "\"foo\"", ""};
+        assertEquals(5, A.mSetArgs.length);
+        assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+        A.reset();
+    }*/
+
+    /* Test repeat command "A/"
+     *//*
+    public void testRepeat() throws Exception {
+        HandlerTest A = new HandlerTest(0, 0, 0, 0, 0);
+        mParser.register('A', A);
+
+        // Try repeated command on fresh parser
+        assertTrue(Arrays.equals(
+                   new String[]{},
+                   mParser.process("A/").toStrings()));
+        assertFalse(A.wasCalled());
+        A.reset();
+
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("ATA").toStrings()));
+        assertTrue(A.mBasicCalled);
+        assertEquals("", A.mBasicArgs);
+        A.reset();
+
+        // Now repeat the command
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("A/").toStrings()));
+        assertTrue(A.mBasicCalled);
+        assertEquals("", A.mBasicArgs);
+        A.reset();
+
+        // Multiple repeats
+        assertTrue(Arrays.equals(
+                   new String[]{"OK"},
+                   mParser.process("A/").toStrings()));
+        assertTrue(A.mBasicCalled);
+        assertEquals("", A.mBasicArgs);
+        A.reset();
+
+    }*/
+}
diff --git a/tests/CoreTests/android/core/BooleanTest.java b/tests/CoreTests/android/core/BooleanTest.java
new file mode 100644
index 0000000..211947e
--- /dev/null
+++ b/tests/CoreTests/android/core/BooleanTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests some basic functionality of Booleans.
+ */
+public class BooleanTest extends TestCase {
+
+    @SmallTest
+    public void testBoolean() throws Exception {
+        Boolean a = new Boolean(true);
+        Boolean b = new Boolean("True");
+        Boolean c = new Boolean(false);
+        Boolean d = new Boolean("Yes");
+
+        assertEquals(a, b);
+        assertEquals(c, d);
+        assertTrue(a.booleanValue());
+        assertFalse(c.booleanValue());
+        assertEquals("true", a.toString());
+        assertEquals("false", c.toString());
+        assertEquals(Boolean.TRUE, a);
+        assertEquals(Boolean.FALSE, c);
+        assertSame(Boolean.valueOf(true), Boolean.TRUE);
+        assertSame(Boolean.valueOf(false), Boolean.FALSE);
+    }
+}
+
diff --git a/tests/CoreTests/android/core/BufferedInputStreamTest.java b/tests/CoreTests/android/core/BufferedInputStreamTest.java
new file mode 100644
index 0000000..1ad95a1
--- /dev/null
+++ b/tests/CoreTests/android/core/BufferedInputStreamTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests to verify that simple functionality works for BufferedInputStreams.
+ */
+public class BufferedInputStreamTest extends TestCase {
+
+    @SmallTest
+    public void testBufferedInputStream() throws Exception {
+        String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz";
+        ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream da = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream ea = new ByteArrayInputStream(str.getBytes());
+
+        BufferedInputStream a = new BufferedInputStream(aa, 6);
+        try {
+            assertEquals(str, IOUtil.read(a));
+        } finally {
+            a.close();
+        }
+
+        BufferedInputStream b = new BufferedInputStream(ba, 7);
+        try {
+            assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+        } finally {
+            b.close();
+        }
+
+        BufferedInputStream c = new BufferedInputStream(ca, 9);
+        try {
+            assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c));
+        } finally {
+            c.close();
+        }
+
+        BufferedInputStream d = new BufferedInputStream(da, 9);
+        try {
+            assertEquals('A', d.read());
+            d.mark(15);
+            assertEquals('b', d.read());
+            assertEquals('C', d.read());
+            d.reset();
+            assertEquals('b', d.read());
+        } finally {
+            d.close();
+        }
+
+        BufferedInputStream e = new BufferedInputStream(ea, 11);
+        try {
+            // test that we can ask for more than is present, and that we'll get
+            // back only what is there.
+            assertEquals(str, IOUtil.read(e, 10000));
+        } finally {
+            e.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/BufferedOutputStreamTest.java b/tests/CoreTests/android/core/BufferedOutputStreamTest.java
new file mode 100644
index 0000000..cd8ec08
--- /dev/null
+++ b/tests/CoreTests/android/core/BufferedOutputStreamTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests to verify that simple functionality works for BufferedOutputStreams.
+ */
+public class BufferedOutputStreamTest extends TestCase {
+
+    @SmallTest
+    public void testBufferedOutputStream() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        ByteArrayOutputStream aa = new ByteArrayOutputStream();
+        BufferedOutputStream a = new BufferedOutputStream(aa, 15);
+        try {
+            a.write(str.getBytes(), 0, 26);
+            a.write('A');
+
+            assertEquals(26, aa.size());
+            assertEquals(aa.toString(), str);
+
+            a.flush();
+
+            assertEquals(27, aa.size());
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzA", aa.toString());
+        } finally {
+            a.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/BufferedReaderTest.java b/tests/CoreTests/android/core/BufferedReaderTest.java
new file mode 100644
index 0000000..a94ca02
--- /dev/null
+++ b/tests/CoreTests/android/core/BufferedReaderTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedReader;
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Tests to verify that simple functionality works for BufferedReaders.
+ */
+public class BufferedReaderTest extends TestCase {
+
+    @MediumTest
+    public void testBufferedReader() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        StringReader aa = new StringReader(str);
+        StringReader ba = new StringReader(str);
+        StringReader ca = new StringReader(str);
+        StringReader da = new StringReader(str);
+
+        BufferedReader a = new BufferedReader(aa, 5);
+        try {
+            assertEquals(str, IOUtil.read(a));
+        } finally {
+            a.close();
+        }
+
+        BufferedReader b = new BufferedReader(ba, 15);
+        try {
+            assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+        } finally {
+            b.close();
+        }
+
+        BufferedReader c = new BufferedReader(ca);
+        try {
+            assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+        } finally {
+            c.close();
+        }
+
+        BufferedReader d = new BufferedReader(da);
+        try {
+            assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+        } finally {
+            d.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/BufferedWriterTest.java b/tests/CoreTests/android/core/BufferedWriterTest.java
new file mode 100644
index 0000000..12dfcef2
--- /dev/null
+++ b/tests/CoreTests/android/core/BufferedWriterTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedWriter;
+import java.io.StringWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Some basic tests for BufferedWriter.
+ */
+public class BufferedWriterTest extends TestCase {
+
+    @SmallTest
+    public void testBufferedWriter() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        StringWriter aa = new StringWriter();
+
+        BufferedWriter a = new BufferedWriter(aa, 20);
+        try {
+            a.write(str.toCharArray(), 0, 26);
+            a.write('X');
+            a.flush();
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", aa.toString());
+
+            a.write("alphabravodelta", 5, 5);
+            a.flush();
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravo", aa.toString());
+            a.newLine();
+            a.write("I'm on a new line.");
+            a.flush();
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravo\nI\'m on a new line.", aa.toString());
+        } finally {
+            a.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/ByteArrayInputStreamTest.java b/tests/CoreTests/android/core/ByteArrayInputStreamTest.java
new file mode 100644
index 0000000..d964102
--- /dev/null
+++ b/tests/CoreTests/android/core/ByteArrayInputStreamTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests to verify that simple functionality works for ByteArrayInputStreams.
+ */
+public class ByteArrayInputStreamTest extends TestCase {
+
+    @SmallTest
+    public void testByteArrayInputStream() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+
+        ByteArrayInputStream a = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream b = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream c = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream d = new ByteArrayInputStream(str.getBytes());
+
+        assertEquals(str, IOUtil.read(a));
+        assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+        assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+        assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+    }
+}
diff --git a/tests/CoreTests/android/core/ByteArrayOutputStreamTest.java b/tests/CoreTests/android/core/ByteArrayOutputStreamTest.java
new file mode 100644
index 0000000..e605214
--- /dev/null
+++ b/tests/CoreTests/android/core/ByteArrayOutputStreamTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * A basic test for ByteArrayOutputStraem.
+ */
+public class ByteArrayOutputStreamTest extends TestCase {
+
+    @SmallTest
+    public void testByteArrayOutputStream() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        ByteArrayOutputStream a = new ByteArrayOutputStream();
+        ByteArrayOutputStream b = new ByteArrayOutputStream(10);
+
+        a.write(str.getBytes(), 0, 26);
+        a.write('X');
+        a.writeTo(b);
+
+        assertEquals(27, a.size());
+        assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString());
+        assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", b.toString());
+    }
+}
diff --git a/tests/CoreTests/android/core/CharArrayReaderTest.java b/tests/CoreTests/android/core/CharArrayReaderTest.java
new file mode 100644
index 0000000..50a217a
--- /dev/null
+++ b/tests/CoreTests/android/core/CharArrayReaderTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.CharArrayReader;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Basic tests for CharArrayReader.
+ */
+public class CharArrayReaderTest extends TestCase {
+
+    @SmallTest
+    public void testCharArrayReader() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        CharArrayReader a = new CharArrayReader(str.toCharArray());
+        CharArrayReader b = new CharArrayReader(str.toCharArray());
+        CharArrayReader c = new CharArrayReader(str.toCharArray());
+        CharArrayReader d = new CharArrayReader(str.toCharArray());
+
+        assertEquals(str, IOUtil.read(a));
+        assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+        assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+        assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+    }
+}
diff --git a/tests/CoreTests/android/core/CharArrayWriterTest.java b/tests/CoreTests/android/core/CharArrayWriterTest.java
new file mode 100644
index 0000000..0aae1e4
--- /dev/null
+++ b/tests/CoreTests/android/core/CharArrayWriterTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.CharArrayWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Basic tests for CharArrayWriter.
+ */
+public class CharArrayWriterTest extends TestCase {
+
+    @SmallTest
+    public void testCharArrayWriter() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        CharArrayWriter a = new CharArrayWriter();
+        CharArrayWriter b = new CharArrayWriter();
+
+        a.write(str, 0, 26);
+        a.write('X');
+        a.writeTo(b);
+
+        assertEquals(27, a.size());
+        assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString());
+
+        b.write("alphabravodelta", 5, 5);
+        b.append('X');
+        assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", b.toString());
+        b.append("omega");
+        assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", b.toString());
+    }
+}
diff --git a/tests/CoreTests/android/core/ChecksumTest.java b/tests/CoreTests/android/core/ChecksumTest.java
new file mode 100644
index 0000000..24fb739
--- /dev/null
+++ b/tests/CoreTests/android/core/ChecksumTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.util.zip.Adler32;
+import java.util.zip.CRC32;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * tests for CRC32 and Adler32 checksum algorithms.
+ */
+public class ChecksumTest extends TestCase {
+
+    @SmallTest
+    public void testChecksum() throws Exception {
+        /*
+         * Values computed experimentally, using C interfaces.
+         */
+        adler32Test(mTestString, 0x9de210dbL);
+        cRC32Test(mTestString, 0x939f04afL);
+
+        // Test for issue 1016037
+        wrongChecksumWithAdler32Test();
+    }
+
+    private void adler32Test(byte[] values, long expected) {
+        Adler32 adler = new Adler32();
+
+        // try it all at once
+        adler.update(values);
+        assertEquals(adler.getValue(), expected);
+
+        // try resetting and computing one byte at a time
+        adler.reset();
+        for (int i = 0; i < values.length; i++) {
+            adler.update(values[i]);
+        }
+        assertEquals(adler.getValue(), expected);
+    }
+
+    private void cRC32Test(byte[] values, long expected) {
+        CRC32 crc = new CRC32();
+
+        // try it all at once
+        crc.update(values);
+        assertEquals(crc.getValue(), expected);
+
+        // try resetting and computing one byte at a time
+        crc.reset();
+        for (int i = 0; i < values.length; i++) {
+            crc.update(values[i]);
+        }
+        assertEquals(crc.getValue(), expected);
+    }
+
+    // "The quick brown fox jumped over the lazy dogs\n"
+    private static byte[] mTestString = {
+            0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63,
+            0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20,
+            0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70,
+            0x65, 0x64, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20,
+            0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79,
+            0x20, 0x64, 0x6f, 0x67, 0x73, 0x2e, 0x0a
+    };
+
+
+    // Test for issue 1016037
+    private void wrongChecksumWithAdler32Test() {
+        byte[] bytes = {1, 0, 5, 0, 15, 0, 1, 11, 0, 1};
+        Adler32 adler = new Adler32();
+        adler.update(bytes);
+        long arrayChecksum = adler.getValue();
+        adler.reset();
+        for (int i = 0; i < bytes.length; i++) {
+            adler.update(bytes[i]);
+        }
+        assertEquals("Checksums not equal: expected: " + arrayChecksum +
+                " actual: " + adler.getValue(), arrayChecksum, adler.getValue());
+    }
+}
+
diff --git a/tests/CoreTests/android/core/ClassLoaderTest.java b/tests/CoreTests/android/core/ClassLoaderTest.java
new file mode 100644
index 0000000..5e7f5a48
--- /dev/null
+++ b/tests/CoreTests/android/core/ClassLoaderTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Test for basic ClassLoader functionality.
+ */
+@Suppress
+public class ClassLoaderTest extends TestCase {
+    /*
+    package my.pkg;
+    public class CLTest {
+        public CLTest() {}
+
+        public String test() { return "This is test 1"; }
+    }
+    */
+    static private byte[] test1class = {
+            (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x31,
+            (byte) 0x00, (byte) 0x11, (byte) 0x0a, (byte) 0x00,
+            (byte) 0x04, (byte) 0x00, (byte) 0x0d, (byte) 0x08,
+            (byte) 0x00, (byte) 0x0e, (byte) 0x07, (byte) 0x00,
+            (byte) 0x0f, (byte) 0x07, (byte) 0x00, (byte) 0x10,
+            (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x3c,
+            (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74,
+            (byte) 0x3e, (byte) 0x01, (byte) 0x00, (byte) 0x03,
+            (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01,
+            (byte) 0x00, (byte) 0x04, (byte) 0x43, (byte) 0x6f,
+            (byte) 0x64, (byte) 0x65, (byte) 0x01, (byte) 0x00,
+            (byte) 0x0f, (byte) 0x4c, (byte) 0x69, (byte) 0x6e,
+            (byte) 0x65, (byte) 0x4e, (byte) 0x75, (byte) 0x6d,
+            (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54,
+            (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65,
+            (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x74,
+            (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01,
+            (byte) 0x00, (byte) 0x14, (byte) 0x28, (byte) 0x29,
+            (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61,
+            (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53,
+            (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e,
+            (byte) 0x67, (byte) 0x3b, (byte) 0x01, (byte) 0x00,
+            (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x75,
+            (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46,
+            (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x01,
+            (byte) 0x00, (byte) 0x0b, (byte) 0x43, (byte) 0x4c,
+            (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
+            (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x0c, (byte) 0x00, (byte) 0x05,
+            (byte) 0x00, (byte) 0x06, (byte) 0x01, (byte) 0x00,
+            (byte) 0x0e, (byte) 0x54, (byte) 0x68, (byte) 0x69,
+            (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73,
+            (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x73,
+            (byte) 0x74, (byte) 0x20, (byte) 0x31, (byte) 0x01,
+            (byte) 0x00, (byte) 0x0d, (byte) 0x6d, (byte) 0x79,
+            (byte) 0x2f, (byte) 0x70, (byte) 0x6b, (byte) 0x67,
+            (byte) 0x2f, (byte) 0x43, (byte) 0x4c, (byte) 0x54,
+            (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01,
+            (byte) 0x00, (byte) 0x10, (byte) 0x6a, (byte) 0x61,
+            (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c,
+            (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f,
+            (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65,
+            (byte) 0x63, (byte) 0x74, (byte) 0x00, (byte) 0x21,
+            (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x04,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x07,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
+            (byte) 0x2a, (byte) 0xb7, (byte) 0x00, (byte) 0x01,
+            (byte) 0xb1, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+            (byte) 0x09, (byte) 0x00, (byte) 0x0a, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x07, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x12,
+            (byte) 0x02, (byte) 0xb0, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x08,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0c
+    };
+
+    /*
+    package my.pkg;
+    public class CLTest {
+        public CLTest() {}
+
+        public String test() { return "This is test 2"; }
+    }
+    */
+    static private byte[] test2class = {
+            (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x31,
+            (byte) 0x00, (byte) 0x11, (byte) 0x0a, (byte) 0x00,
+            (byte) 0x04, (byte) 0x00, (byte) 0x0d, (byte) 0x08,
+            (byte) 0x00, (byte) 0x0e, (byte) 0x07, (byte) 0x00,
+            (byte) 0x0f, (byte) 0x07, (byte) 0x00, (byte) 0x10,
+            (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x3c,
+            (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74,
+            (byte) 0x3e, (byte) 0x01, (byte) 0x00, (byte) 0x03,
+            (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01,
+            (byte) 0x00, (byte) 0x04, (byte) 0x43, (byte) 0x6f,
+            (byte) 0x64, (byte) 0x65, (byte) 0x01, (byte) 0x00,
+            (byte) 0x0f, (byte) 0x4c, (byte) 0x69, (byte) 0x6e,
+            (byte) 0x65, (byte) 0x4e, (byte) 0x75, (byte) 0x6d,
+            (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54,
+            (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65,
+            (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x74,
+            (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01,
+            (byte) 0x00, (byte) 0x14, (byte) 0x28, (byte) 0x29,
+            (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61,
+            (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53,
+            (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e,
+            (byte) 0x67, (byte) 0x3b, (byte) 0x01, (byte) 0x00,
+            (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x75,
+            (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46,
+            (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x01,
+            (byte) 0x00, (byte) 0x0b, (byte) 0x43, (byte) 0x4c,
+            (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
+            (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
+            (byte) 0x61, (byte) 0x0c, (byte) 0x00, (byte) 0x05,
+            (byte) 0x00, (byte) 0x06, (byte) 0x01, (byte) 0x00,
+            (byte) 0x0e, (byte) 0x54, (byte) 0x68, (byte) 0x69,
+            (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73,
+            (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x73,
+            (byte) 0x74, (byte) 0x20, (byte) 0x32, (byte) 0x01,
+            (byte) 0x00, (byte) 0x0d, (byte) 0x6d, (byte) 0x79,
+            (byte) 0x2f, (byte) 0x70, (byte) 0x6b, (byte) 0x67,
+            (byte) 0x2f, (byte) 0x43, (byte) 0x4c, (byte) 0x54,
+            (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01,
+            (byte) 0x00, (byte) 0x10, (byte) 0x6a, (byte) 0x61,
+            (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c,
+            (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f,
+            (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65,
+            (byte) 0x63, (byte) 0x74, (byte) 0x00, (byte) 0x21,
+            (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x04,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x07,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
+            (byte) 0x2a, (byte) 0xb7, (byte) 0x00, (byte) 0x01,
+            (byte) 0xb1, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+            (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+            (byte) 0x09, (byte) 0x00, (byte) 0x0a, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x07, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0x00,
+            (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+            (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x12,
+            (byte) 0x02, (byte) 0xb0, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x08,
+            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06,
+            (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01,
+            (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x00,
+            (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0c
+    };
+
+    /*
+     * Custom class loader.
+     */
+    private class MyLoader extends ClassLoader {
+        public MyLoader(byte[] data) {
+            super();
+            mData = data;
+        }
+
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            assertEquals("my.pkg.CLTest", name);
+            return defineClass(name, mData, 0, mData.length);
+        }
+
+        byte[] mData;
+    }
+
+
+    /*
+     * Simple test: manually load two class files that have the same class
+     * name but different contents.
+     */
+    public void testClassLoader() throws Exception {
+        Class test1, test2;
+        MyLoader loader1 = new MyLoader(test1class);
+        MyLoader loader2 = new MyLoader(test2class);
+
+        test1 = loader1.loadClass("my.pkg.CLTest");
+        test2 = loader2.loadClass("my.pkg.CLTest");
+
+        methodTest(test1, "This is test 1");
+        methodTest(test2, "This is test 2");
+    }
+
+    /*
+     * Invoke the test() method and verify that the string returned
+     * matches what we expect.
+     */
+    private static void methodTest(Class clazz, String expect)
+            throws NoSuchMethodException, InstantiationException,
+            IllegalAccessException, InvocationTargetException {
+        Method meth = clazz.getMethod("test", (Class[]) null);
+        Object obj = clazz.newInstance();
+        Object result = meth.invoke(obj, (Object[]) null);
+
+        assertEquals(result, expect);
+    }
+}
+
diff --git a/tests/CoreTests/android/core/ClassTest.java b/tests/CoreTests/android/core/ClassTest.java
new file mode 100644
index 0000000..cc1b4ca
--- /dev/null
+++ b/tests/CoreTests/android/core/ClassTest.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.widget.Button;
+import junit.framework.TestCase;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Set;
+
+
+class ClassWithPrivateConstructor {
+    private ClassWithPrivateConstructor() {
+    }
+}
+
+public class ClassTest extends TestCase {
+
+    @SmallTest
+    public void testClass() throws Exception {
+        // Now, never mind the fact that most of this stuff has to work
+        // for the test harness to get this far....
+
+        //System.out.println("Class.forName()");
+        Class helloClass = Class.forName(ClassTest.class.getName());
+
+        //System.out.println("Class.newInstance()");
+        Object instance = helloClass.newInstance();
+        assertNotNull(instance);
+
+        //System.out.println("Class.forName() nonexisting class");
+        try {
+            Class.forName("this.class.DoesNotExist");
+            fail("unexpected success");
+        } catch (ClassNotFoundException ex) {
+            // expected
+        }
+
+        //System.out.println("Class.newInstance() private constructor");
+        try {
+            Class.forName("android.core.ClassWithPrivateConstructor").newInstance();
+            fail("unexpected success");
+        } catch (IllegalAccessException ex) {
+            // this is expected
+        }
+
+        //System.out.println("Class.getDeclaredMethod()");
+
+        Method method = helloClass.getDeclaredMethod("method", (Class[]) null);
+
+        method.invoke(new ClassTest(), (Object[]) null);
+
+        //System.out.println("Class.getDeclaredMethod() w/ args");
+
+        method = helloClass.getDeclaredMethod("methodWithArgs", Object.class);
+
+        Object invokeArgs[] = new Object[1];
+        invokeArgs[0] = "Hello";
+        Object ret = method.invoke(new ClassTest(), invokeArgs);
+        assertEquals(ret, invokeArgs[0]);
+
+        //System.out.println("Class.getDeclaredMethod() -- private");
+
+        method = helloClass.getDeclaredMethod("privateMethod", (Class[]) null);
+
+        method.invoke(new ClassTest(), (Object[]) null);
+        //fail("unexpected success");
+        // TODO: I think this actually *should* succeed, because the
+        // call to the private method is being made from the same class.
+        // This needs to be replaced with a private call to a different
+        // class.
+
+        //System.out.println("Class.getSuperclass");
+        Class objectClass = Class.forName("java.lang.Object");
+        assertEquals(helloClass.getSuperclass().getSuperclass().getSuperclass(), objectClass);
+
+        //System.out.println("Class.isAssignableFrom");
+        assertTrue(objectClass.isAssignableFrom(helloClass));
+        assertFalse(helloClass.isAssignableFrom(objectClass));
+
+        //System.out.println("Class.getConstructor");
+
+        Constructor constructor = helloClass.getConstructor((Class[]) null);
+        assertNotNull(constructor);
+
+        //System.out.println("Class.getModifiers");
+
+        assertTrue(Modifier.isPublic(helloClass.getModifiers()));
+        //System.out.println("Modifiers: " + Modifier.toString(helloClass.getModifiers()));
+
+        //System.out.println("Class.getMethod");
+
+        helloClass.getMethod("method", (Class[]) null);
+
+        try {
+            Class[] argTypes = new Class[1];
+            argTypes[0] = helloClass;
+            helloClass.getMethod("method", argTypes);
+            fail("unexpected success");
+        } catch (NoSuchMethodException ex) {
+            // exception expected
+        }
+
+        // Test for public tracker issue 14
+        SimpleClass obj = new SimpleClass();
+        Field field = obj.getClass().getDeclaredField("str");
+        field.set(obj, null);
+    }
+
+    public class SimpleClass {
+        public String str;
+    }
+
+    public Object methodWithArgs(Object o) {
+        return o;
+    }
+
+    boolean methodInvoked;
+
+    public void method() {
+        methodInvoked = true;
+    }
+
+    boolean privateMethodInvoked;
+
+    public void privateMethod() {
+        privateMethodInvoked = true;
+    }
+
+    // Regression for 1018067: Class.getMethods() returns the same method over
+    // and over again from all base classes
+    @MediumTest
+    public void testClassGetMethodsNoDupes() {
+        Method[] methods = Button.class.getMethods();
+        Set<String> set = new HashSet<String>();
+
+        for (int i = 0; i < methods.length; i++) {
+            String signature = methods[i].toString();
+
+            int par = signature.indexOf('(');
+            int dot = signature.lastIndexOf('.', par);
+
+            signature = signature.substring(dot + 1);
+
+            assertFalse("Duplicate " + signature, set.contains(signature));
+            set.add(signature);
+        }
+    }
+
+    interface MyInterface {
+        void foo();
+    }
+
+    interface MyOtherInterface extends MyInterface {
+        void bar();
+    }
+
+    abstract class MyClass implements MyOtherInterface {
+        public void gabba() {
+        }
+
+        public void hey() {
+        }
+    }
+
+    // Check if we also reflect methods from interfaces
+    @SmallTest
+    public void testGetMethodsInterfaces() {
+        Method[] methods = MyInterface.class.getMethods();
+        assertTrue("Interface method must be there", hasMethod(methods, ".foo("));
+
+        methods = MyOtherInterface.class.getMethods();
+        assertTrue("Interface method must be there", hasMethod(methods, ".foo("));
+        assertTrue("Interface method must be there", hasMethod(methods, ".bar("));
+
+        methods = MyClass.class.getMethods();
+        assertTrue("Interface method must be there", hasMethod(methods, ".foo("));
+        assertTrue("Interface method must be there", hasMethod(methods, ".bar("));
+
+        assertTrue("Declared method must be there", hasMethod(methods, ".gabba("));
+        assertTrue("Declared method must be there", hasMethod(methods, ".hey("));
+
+        assertTrue("Inherited method must be there", hasMethod(methods, ".toString("));
+    }
+
+    private boolean hasMethod(Method[] methods, String signature) {
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].toString().contains(signature)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    // Test for Class.getPackage();
+    @SmallTest
+    public void testClassGetPackage() {
+        assertNotNull("Package must be non-null", getClass().getPackage());
+        assertEquals("Package must have expected name", "android.core", getClass().getPackage().getName());
+        assertEquals("Package must have expected title", "Unknown", getClass().getPackage().getSpecificationTitle());
+
+        Package p = java.lang.Object.class.getPackage();
+        assertNotNull("Package must be non-null", p);
+        assertEquals("Package must have expected name", "java.lang", p.getName());
+        assertSame("Package object must be same for each call", p, java.lang.Object.class.getPackage());
+    }
+    
+    // Regression test for #1123708: Problem with getCanonicalName(),
+    // getSimpleName(), and getPackage().
+    //
+    // A couple of interesting cases need to be checked: Top-level classes,
+    // member classes, local classes, and anonymous classes. Also, boundary
+    // cases with '$' in the class names are checked, since the '$' is used
+    // as the separator between outer and inner class, so this might lead
+    // to problems (it did in the previous implementation).
+    // 
+    // Caution: Adding local or anonymous classes elsewhere in this
+    // file might affect the test.
+    private class MemberClass {
+        // This space intentionally left blank.
+    }
+
+    private class Mi$o$oup {
+        // This space intentionally left blank.
+    }
+    
+    @SmallTest
+    public void testVariousClassNames() {
+        Class<?> clazz = this.getClass();
+        String pkg = (clazz.getPackage() == null ? "" : clazz.getPackage().getName() + ".");
+
+        // Simple, top-level class
+        
+        assertEquals("Top-level class name must be correct", pkg + "ClassTest", clazz.getName());
+        assertEquals("Top-level class simple name must be correct", "ClassTest", clazz.getSimpleName());
+        assertEquals("Top-level class canonical name must be correct", pkg + "ClassTest", clazz.getCanonicalName());
+
+        clazz = MemberClass.class;
+        
+        assertEquals("Member class name must be correct", pkg + "ClassTest$MemberClass", clazz.getName());
+        assertEquals("Member class simple name must be correct", "MemberClass", clazz.getSimpleName());
+        assertEquals("Member class canonical name must be correct", pkg + "ClassTest.MemberClass", clazz.getCanonicalName());
+        
+        class LocalClass {
+            // This space intentionally left blank.
+        }
+
+        clazz = LocalClass.class;
+
+        assertEquals("Local class name must be correct", pkg + "ClassTest$1LocalClass", clazz.getName());
+        assertEquals("Local class simple name must be correct", "LocalClass", clazz.getSimpleName());
+        assertNull("Local class canonical name must be null", clazz.getCanonicalName());
+
+        clazz = new Object() { }.getClass();
+
+        assertEquals("Anonymous class name must be correct", pkg + "ClassTest$1", clazz.getName());
+        assertEquals("Anonymous class simple name must be empty", "", clazz.getSimpleName());
+        assertNull("Anonymous class canonical name must be null", clazz.getCanonicalName());
+
+        // Weird special cases with dollar in name.
+
+        clazz = Mou$$aka.class;
+        
+        assertEquals("Top-level class name must be correct", pkg + "Mou$$aka", clazz.getName());
+        assertEquals("Top-level class simple name must be correct", "Mou$$aka", clazz.getSimpleName());
+        assertEquals("Top-level class canonical name must be correct", pkg + "Mou$$aka", clazz.getCanonicalName());
+        
+        clazz = Mi$o$oup.class;
+        
+        assertEquals("Member class name must be correct", pkg + "ClassTest$Mi$o$oup", clazz.getName());
+        assertEquals("Member class simple name must be correct", "Mi$o$oup", clazz.getSimpleName());
+        assertEquals("Member class canonical name must be correct", pkg + "ClassTest.Mi$o$oup", clazz.getCanonicalName());
+        
+        class Ma$hedPotatoe$ {
+            // This space intentionally left blank.
+        }
+
+        clazz = Ma$hedPotatoe$.class;
+        
+        assertEquals("Member class name must be correct", pkg + "ClassTest$1Ma$hedPotatoe$", clazz.getName());
+        assertEquals("Member class simple name must be correct", "Ma$hedPotatoe$", clazz.getSimpleName());
+        assertNull("Member class canonical name must be null", clazz.getCanonicalName());
+    }
+
+    @SmallTest
+    public void testLocalMemberClass() {
+        Class<?> clazz = this.getClass();
+
+        assertFalse("Class must not be member", clazz.isMemberClass());  
+        assertFalse("Class must not be local", clazz.isLocalClass());  
+        
+        clazz = MemberClass.class;
+
+        assertTrue("Class must be member", clazz.isMemberClass());  
+        assertFalse("Class must not be local", clazz.isLocalClass());  
+        
+        class OtherLocalClass {
+            // This space intentionally left blank.
+        }
+
+        clazz = OtherLocalClass.class;
+
+        assertFalse("Class must not be member", clazz.isMemberClass());  
+        assertTrue("Class must be local", clazz.isLocalClass());  
+        
+        clazz = new Object() { }.getClass();
+
+        assertFalse("Class must not be member", clazz.isMemberClass());  
+        assertFalse("Class must not be local", clazz.isLocalClass());  
+    }
+
+}
+
+class Mou$$aka {
+    // This space intentionally left blank.
+}
diff --git a/tests/CoreTests/android/core/CoreTests.java b/tests/CoreTests/android/core/CoreTests.java
new file mode 100644
index 0000000..e4f835c
--- /dev/null
+++ b/tests/CoreTests/android/core/CoreTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import com.android.internal.telephony.TelephonyTests;
+
+import junit.framework.TestSuite;
+
+import android.graphics.ColorStateListTest;
+import android.location.LocationManagerProximityTest;
+import android.location.LocationTest;
+import android.test.AndroidTestRunnerTest;
+import android.test.InstrumentationTestRunnerTest;
+import android.util.*;
+import android.view.FocusFinderTest;
+import android.view.ViewGroupAttributesTest;
+import android.webkit.*;
+
+public class CoreTests extends TestSuite {
+    
+    /**
+     * To run these tests:
+     * $ mmm java/tests && adb sync
+     * $ adb shell am instrument -w \
+     *    -e class android.core.CoreTests \
+     *    android.core/android.test.InstrumentationTestRunner
+     */
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(CoreTests.class.getName());
+
+        // Re-enable StateListDrawableTest when we are running in the
+        // framework-test directory which allows access to package private
+        // access for MockView
+        // suite.addTestSuite(StateListDrawableTest.class);
+        suite.addTestSuite(DayOfMonthCursorTest.class);
+        suite.addTestSuite(MonthDisplayHelperTest.class);
+        suite.addTestSuite(StateSetTest.class);
+        suite.addTestSuite(ColorStateListTest.class);
+        suite.addTestSuite(FocusFinderTest.class);
+        suite.addTestSuite(ViewGroupAttributesTest.class);
+        suite.addTest(TelephonyTests.suite());
+        suite.addTestSuite(FloatMathTest.class);
+        suite.addTest(JavaTests.suite());
+        suite.addTestSuite(LocationTest.class);
+        suite.addTestSuite(LocationManagerProximityTest.class);
+        suite.addTestSuite(AndroidTestRunnerTest.class);
+        suite.addTestSuite(InstrumentationTestRunnerTest.class);
+        suite.addTestSuite(CookieTest.class);
+        
+        return suite;
+    }
+}
diff --git a/tests/CoreTests/android/core/CryptoTest.java b/tests/CoreTests/android/core/CryptoTest.java
new file mode 100644
index 0000000..f00d49f
--- /dev/null
+++ b/tests/CoreTests/android/core/CryptoTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigest;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.crypto.digests.MD2Digest;
+import org.bouncycastle.crypto.digests.MD4Digest;
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Implements unit tests for our JNI wrapper around OpenSSL. We use the
+ * existing Bouncy Castle implementation as our test oracle.
+ */
+public class CryptoTest extends TestCase {
+
+    /**
+     * Processes the two given message digests for the same data and checks
+     * the results. Requirement is that the results must be equal, the digest
+     * implementations must have the same properties, and the new implementation
+     * must be faster than the old one.
+     * 
+     * @param oldDigest The old digest implementation, provided by Bouncy Castle 
+     * @param newDigest The new digest implementation, provided by OpenSSL
+     */
+    public void doTestMessageDigest(Digest oldDigest, Digest newDigest) {
+        final int ITERATIONS = 10;
+        
+        byte[] data = new byte[1024];
+        
+        byte[] oldHash = new byte[oldDigest.getDigestSize()];
+        byte[] newHash = new byte[newDigest.getDigestSize()];
+        
+        Assert.assertEquals("Hash names must be equal", oldDigest.getAlgorithmName(), newDigest.getAlgorithmName());
+        Assert.assertEquals("Hash sizes must be equal", oldHash.length, newHash.length);
+        Assert.assertEquals("Hash block sizes must be equal", ((ExtendedDigest)oldDigest).getByteLength(), ((ExtendedDigest)newDigest).getByteLength());
+        for (int i = 0; i < data.length; i++) {
+            data[i] = (byte)i;
+        }
+
+        long oldTime = 0;
+        long newTime = 0;
+        
+        for (int j = 0; j < ITERATIONS; j++) {
+            long t0 = System.currentTimeMillis();
+            for (int i = 0; i < 4; i++) {
+                oldDigest.update(data, 0, data.length);
+            }
+            int oldLength = oldDigest.doFinal(oldHash, 0);
+            long t1 = System.currentTimeMillis();
+    
+            oldTime = oldTime + (t1 - t0);
+            
+            long t2 = System.currentTimeMillis();
+            for (int i = 0; i < 4; i++) {
+                newDigest.update(data, 0, data.length);
+            }
+            int newLength = newDigest.doFinal(newHash, 0);
+            long t3 = System.currentTimeMillis();
+
+            newTime = newTime + (t3 - t2);
+            
+            Assert.assertEquals("Hash sizes must be equal", oldLength, newLength);
+    
+            for (int i = 0; i < oldLength; i++) {
+                Assert.assertEquals("Hashes[" + i + "] must be equal", oldHash[i], newHash[i]);
+            }
+        }
+
+        android.util.Log.d("CryptoTest", "Time for " + ITERATIONS + " x old hash processing: " + oldTime + " ms");
+        android.util.Log.d("CryptoTest", "Time for " + ITERATIONS + " x new hash processing: " + newTime + " ms");
+        
+        // Assert.assertTrue("New hash should be faster", newTime < oldTime);
+    }
+
+    /**
+     * Tests the MD2 implementation.
+     */
+    @LargeTest
+    public void testMD2() {
+        Digest oldDigest = new MD2Digest();
+        Digest newDigest = OpenSSLMessageDigest.getInstance("MD2");
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+    
+    /**
+     * Tests the MD4 implementation.
+     */
+    @MediumTest
+    public void testMD4() {
+        Digest oldDigest = new MD4Digest();
+        Digest newDigest = OpenSSLMessageDigest.getInstance("MD4");
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+    
+    /**
+     * Tests the MD5 implementation.
+     */
+    @MediumTest
+    public void testMD5() {
+        Digest oldDigest = new MD5Digest();
+        Digest newDigest = OpenSSLMessageDigest.getInstance("MD5");
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+    
+    /**
+     * Tests the SHA-1 implementation.
+     */
+    @MediumTest
+    public void testSHA1() {
+        Digest oldDigest = new SHA1Digest();
+        Digest newDigest = OpenSSLMessageDigest.getInstance("SHA-1");
+        doTestMessageDigest(oldDigest, newDigest);
+    }
+    
+}
diff --git a/tests/CoreTests/android/core/DataInputStreamTest.java b/tests/CoreTests/android/core/DataInputStreamTest.java
new file mode 100644
index 0000000..ca801d6
--- /dev/null
+++ b/tests/CoreTests/android/core/DataInputStreamTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class DataInputStreamTest extends TestCase {
+
+    @SmallTest
+    public void testDataInputStream() throws Exception {
+        String str = "AbCdEfGhIjKlM\nOpQ\rStUvWxYz";
+        ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream da = new ByteArrayInputStream(str.getBytes());
+
+        DataInputStream a = new DataInputStream(aa);
+        try {
+            assertEquals(str, IOUtil.read(a));
+        } finally {
+            a.close();
+        }
+
+        DataInputStream b = new DataInputStream(ba);
+        try {
+            assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+        } finally {
+            b.close();
+        }
+
+        DataInputStream c = new DataInputStream(ca);
+        try {
+            assertEquals("bdfhjl\np\rtvxz", IOUtil.skipRead(c));
+        } finally {
+            c.close();
+        }
+
+        DataInputStream d = new DataInputStream(da);
+        try {
+            assertEquals("AbCdEfGhIjKlM", d.readLine());
+            assertEquals("OpQ", d.readLine());
+            assertEquals("StUvWxYz", d.readLine());
+        } finally {
+            d.close();
+        }
+
+        ByteArrayOutputStream e = new ByteArrayOutputStream();
+        DataOutputStream f = new DataOutputStream(e);
+        try {
+            f.writeBoolean(true);
+            f.writeByte('a');
+            f.writeBytes("BCD");
+            f.writeChar('e');
+            f.writeChars("FGH");
+            f.writeUTF("ijklm");
+            f.writeDouble(1);
+            f.writeFloat(2);
+            f.writeInt(3);
+            f.writeLong(4);
+            f.writeShort(5);
+        } finally {
+            f.close();
+        }
+        
+        ByteArrayInputStream ga = new ByteArrayInputStream(e.toByteArray());
+        DataInputStream g = new DataInputStream(ga);
+
+        try {
+            assertTrue(g.readBoolean());
+            assertEquals('a', g.readByte());
+            assertEquals(2, g.skipBytes(2));
+            assertEquals('D', g.readByte());
+            assertEquals('e', g.readChar());
+            assertEquals('F', g.readChar());
+            assertEquals('G', g.readChar());
+            assertEquals('H', g.readChar());
+            assertEquals("ijklm", g.readUTF());
+            assertEquals(1, g.readDouble(), 0);
+            assertEquals(2f, g.readFloat(), 0f);
+            assertEquals(3, g.readInt());
+            assertEquals(4, g.readLong());
+            assertEquals(5, g.readShort());
+        } finally {
+            g.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/DataOutputStreamTest.java b/tests/CoreTests/android/core/DataOutputStreamTest.java
new file mode 100644
index 0000000..95502b3
--- /dev/null
+++ b/tests/CoreTests/android/core/DataOutputStreamTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Basic tests for DataOutputStreams.
+ */
+public class DataOutputStreamTest extends TestCase {
+
+    @SmallTest
+    public void testDataOutputStream() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        ByteArrayOutputStream aa = new ByteArrayOutputStream();
+        DataOutputStream a = new DataOutputStream(aa);
+
+        try {
+            a.write(str.getBytes(), 0, 26);
+            a.write('A');
+
+            assertEquals(27, aa.size());
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzA", aa.toString());
+
+            a.writeByte('B');
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzAB", aa.toString());
+            a.writeBytes("BYTES");
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzABBYTES", aa.toString());
+        } finally {
+            a.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/DatabaseSessionCache.java b/tests/CoreTests/android/core/DatabaseSessionCache.java
new file mode 100644
index 0000000..c344d9c
--- /dev/null
+++ b/tests/CoreTests/android/core/DatabaseSessionCache.java
@@ -0,0 +1,312 @@
+// Copyright 2009 The Android Open Source Project
+
+package android.core;
+
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+import android.content.ContentValues;
+import android.content.Context;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLSession;
+
+/**
+ * Hook into harmony SSL cache to persist the SSL sessions.
+ *
+ * Current implementation is suitable for saving a small number of hosts -
+ * like google services. It can be extended with expiration and more features
+ * to support more hosts.
+ *
+ * {@hide}
+ */
+public class DatabaseSessionCache implements SSLClientSessionCache {
+    private static final String TAG = "SslSessionCache";
+    static DatabaseHelper sDefaultDatabaseHelper;
+
+    private DatabaseHelper mDatabaseHelper;
+
+    /**
+     * Table where sessions are stored.
+     */
+    public static final String SSL_CACHE_TABLE = "ssl_sessions";
+
+    private static final String SSL_CACHE_ID = "_id";
+
+    /**
+     * Key is host:port - port is not optional.
+     */
+    private static final String SSL_CACHE_HOSTPORT = "hostport";
+
+    /**
+     * Base64-encoded DER value of the session.
+     */
+    private static final String SSL_CACHE_SESSION = "session";
+
+    /**
+     * Time when the record was added - should be close to the time
+     * of the initial session negotiation.
+     */
+    private static final String SSL_CACHE_TIME_SEC = "time_sec";
+
+    public static final String DATABASE_NAME = "ssl_sessions.db";
+
+    public static final int DATABASE_VERSION = 1;
+
+    /** public for testing
+     */
+    public static final int SSL_CACHE_ID_COL = 0;
+    public static final int SSL_CACHE_HOSTPORT_COL = 1;
+    public static final int SSL_CACHE_SESSION_COL = 2;
+    public static final int SSL_CACHE_TIME_SEC_COL = 3;
+
+    private static final String SAVE_ON_ADD = "save_on_add";
+
+    static boolean sHookInitializationDone = false;
+
+    public static final int MAX_CACHE_SIZE = 256;
+
+    private static final Map<String, byte[]> mExternalCache =
+        new LinkedHashMap<String, byte[]>(MAX_CACHE_SIZE, 0.75f, true) {
+        @Override
+        public boolean removeEldestEntry(
+                Map.Entry<String, byte[]> eldest) {
+            boolean shouldDelete = this.size() > MAX_CACHE_SIZE;
+
+            // TODO: delete from DB
+            return shouldDelete;
+        }
+    };
+    static boolean mNeedsCacheLoad = true;
+
+    public static final String[] PROJECTION = new String[] {
+      SSL_CACHE_ID,
+      SSL_CACHE_HOSTPORT,
+      SSL_CACHE_SESSION,
+      SSL_CACHE_TIME_SEC
+    };
+
+    /**
+     * This class needs to be installed as a hook, if the security property
+     * is set. Getting the right classloader may be fun since we don't use
+     * Provider to get its classloader, but in android this is in same
+     * loader with AndroidHttpClient.
+     *
+     * This constructor will use the default database. You must
+     * call init() before to specify the context used for the database and
+     * check settings.
+     */
+    public DatabaseSessionCache() {
+        Log.v(TAG, "Instance created.");
+        // May be null if caching is disabled - no sessions will be persisted.
+        this.mDatabaseHelper = sDefaultDatabaseHelper;
+    }
+
+    /**
+     * Create a SslSessionCache instance, using the specified context to
+     * initialize the database.
+     *
+     * This constructor will use the default database - created the first
+     * time.
+     *
+     * @param activityContext
+     */
+    public DatabaseSessionCache(Context activityContext) {
+        // Static init - only one initialization will happen.
+        // Each SslSessionCache is using the same DB.
+        init(activityContext);
+        // May be null if caching is disabled - no sessions will be persisted.
+        this.mDatabaseHelper = sDefaultDatabaseHelper;
+    }
+
+    /**
+     * Create a SslSessionCache that uses a specific database.
+     *
+     * @param database
+     */
+    public DatabaseSessionCache(DatabaseHelper database) {
+        this.mDatabaseHelper = database;
+    }
+
+//    public static boolean enabled(Context androidContext) {
+//        String sslCache = Settings.Gservices.getString(androidContext.getContentResolver(),
+//                Settings.Gservices.SSL_SESSION_CACHE);
+//
+//        if (Log.isLoggable(TAG, Log.DEBUG)) {
+//            Log.d(TAG, "enabled " + sslCache + " " + androidContext.getPackageName());
+//        }
+//
+//        return SAVE_ON_ADD.equals(sslCache);
+//    }
+
+    /**
+     * You must call this method to enable SSL session caching for an app.
+     */
+    public synchronized static void init(Context activityContext) {
+        // It is possible that multiple provider will try to install this hook.
+        // We want a single db per VM.
+        if (sHookInitializationDone) {
+            return;
+        }
+
+
+//        // More values can be added in future to provide different
+//        // behaviours, like 'batch save'.
+//        if (enabled(activityContext)) {
+            Context appContext = activityContext.getApplicationContext();
+            sDefaultDatabaseHelper = new DatabaseHelper(appContext);
+
+            // Set default SSLSocketFactory
+            // The property is defined in the javadocs for javax.net.SSLSocketFactory
+            // (no constant defined there)
+            // This should cover all code using SSLSocketFactory.getDefault(),
+            // including native http client and apache httpclient.
+            // MCS is using its own custom factory - will need special code.
+//            Security.setProperty("ssl.SocketFactory.provider",
+//                    SslSocketFactoryWithCache.class.getName());
+//        }
+
+        // Won't try again.
+        sHookInitializationDone = true;
+    }
+
+    public void putSessionData(SSLSession session, byte[] der) {
+        if (mDatabaseHelper == null) {
+            return;
+        }
+        if (mExternalCache.size() > MAX_CACHE_SIZE) {
+            // remove oldest.
+            Cursor byTime = mDatabaseHelper.getWritableDatabase().query(SSL_CACHE_TABLE,
+                    PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC);
+            byTime.moveToFirst();
+            // TODO: can I do byTime.deleteRow() ?
+            String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL);
+
+            mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE,
+                    SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort });
+        }
+        // Serialize native session to standard DER encoding
+        long t0 = System.currentTimeMillis();
+
+        String b64 = new String(Base64.encodeBase64(der));
+        String key = session.getPeerHost() + ":" + session.getPeerPort();
+
+        ContentValues values = new ContentValues();
+        values.put(SSL_CACHE_HOSTPORT, key);
+        values.put(SSL_CACHE_SESSION, b64);
+        values.put(SSL_CACHE_TIME_SEC, System.currentTimeMillis() / 1000);
+
+        synchronized (this.getClass()) {
+            mExternalCache.put(key, der);
+
+            try {
+                mDatabaseHelper.getWritableDatabase().insert(SSL_CACHE_TABLE, null /*nullColumnHack */ , values);
+            } catch(SQLException ex) {
+                // Ignore - nothing we can do to recover, and caller shouldn't
+                // be affected.
+                Log.w(TAG, "Ignoring SQL exception when caching session", ex);
+            }
+        }
+        if (Log.isLoggable(TAG, Log.DEBUG)) {
+            long t1 = System.currentTimeMillis();
+            Log.d(TAG, "New SSL session " + session.getPeerHost() +
+                    " DER len: " + der.length + " " + (t1 - t0));
+        }
+
+    }
+
+    public byte[] getSessionData(String host, int port) {
+        // Current (simple) implementation does a single lookup to DB, then saves
+        // all entries to the cache.
+
+        // This works for google services - i.e. small number of certs.
+        // If we extend this to all processes - we should hold a separate cache
+        // or do lookups to DB each time.
+        if (mDatabaseHelper == null) {
+            return null;
+        }
+        synchronized(this.getClass()) {
+            if (mNeedsCacheLoad) {
+                // Don't try to load again, if something is wrong on the first
+                // request it'll likely be wrong each time.
+                mNeedsCacheLoad = false;
+                long t0 = System.currentTimeMillis();
+
+                Cursor cur = null;
+                try {
+                    cur = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE, PROJECTION, null,
+                            null, null, null, null);
+                    if (cur.moveToFirst()) {
+                        do {
+                            String hostPort = cur.getString(SSL_CACHE_HOSTPORT_COL);
+                            String value = cur.getString(SSL_CACHE_SESSION_COL);
+
+                            if (hostPort == null || value == null) {
+                                continue;
+                            }
+                            // TODO: blob support ?
+                            byte[] der = Base64.decodeBase64(value.getBytes());
+                            mExternalCache.put(hostPort, der);
+                        } while (cur.moveToNext());
+
+                    }
+                } catch (SQLException ex) {
+                    Log.d(TAG, "Error loading SSL cached entries ", ex);
+                } finally {
+                    if (cur != null) {
+                        cur.close();
+                    }
+                    if (Log.isLoggable(TAG, Log.DEBUG)) {
+                        long t1 = System.currentTimeMillis();
+                        Log.d(TAG, "LOADED CACHED SSL " + (t1 - t0) + " ms");
+                    }
+                }
+            }
+
+            String key = host + ":" + port;
+
+            return mExternalCache.get(key);
+        }
+    }
+
+    public byte[] getSessionData(byte[] id) {
+        // We support client side only - the cache will do nothing on client.
+        return null;
+    }
+
+    /** Visible for testing.
+     */
+    public static class DatabaseHelper extends SQLiteOpenHelper {
+
+        public DatabaseHelper(Context context) {
+            super(context, DATABASE_NAME, null /* factory */, DATABASE_VERSION);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + SSL_CACHE_TABLE + " (" +
+                    SSL_CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                    SSL_CACHE_HOSTPORT + " TEXT UNIQUE ON CONFLICT REPLACE," +
+                    SSL_CACHE_SESSION + " TEXT," +
+                    SSL_CACHE_TIME_SEC + " INTEGER" +
+            ");");
+            db.execSQL("CREATE INDEX ssl_sessions_idx1 ON ssl_sessions (" +
+                    SSL_CACHE_HOSTPORT + ");");
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE );
+            onCreate(db);
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/tests/CoreTests/android/core/DatagramTest.java b/tests/CoreTests/android/core/DatagramTest.java
new file mode 100644
index 0000000..355a267
--- /dev/null
+++ b/tests/CoreTests/android/core/DatagramTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketTimeoutException;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Implements some simple tests for datagrams. Not as excessive as the core
+ * tests, but good enough for the harness.
+ */
+public class DatagramTest extends TestCase {
+
+    /**
+     * Helper class that listens to incoming datagrams and reflects them to the
+     * sender. Incoming datagram is interpreted as a String. It is uppercased
+     * before being sent back.
+     */
+
+    class Reflector extends Thread {
+        // Helper class for reflecting incoming datagrams. 
+        DatagramSocket socket;
+
+        boolean alive = true;
+
+        byte[] buffer = new byte[256];
+
+        DatagramPacket packet;
+
+        /**
+         * Main loop. Receives datagrams and reflects them.
+         */
+        @Override
+        public void run() {
+            try {
+                while (alive) {
+                    try {
+                        packet.setLength(buffer.length);
+                        socket.receive(packet);
+                        String s = stringFromPacket(packet);
+                        // System.out.println(s + " (from " + packet.getAddress() + ":" + packet.getPort() + ")");
+
+                        try {
+                            Thread.sleep(100);
+                        } catch (InterruptedException ex) {
+                            // Ignore.
+                        }
+
+                        stringToPacket(s.toUpperCase(), packet);
+
+                        packet.setAddress(InetAddress.getLocalHost());
+                        packet.setPort(2345);
+
+                        socket.send(packet);
+                    } catch (java.io.InterruptedIOException e) {
+                    }
+                }
+            } catch (java.io.IOException ex) {
+                ex.printStackTrace();
+            } finally {
+                socket.close();
+            }
+        }
+
+        /**
+         * Creates a new Relfector object for the given local address and port.
+         */
+        public Reflector(int port, InetAddress address) {
+            try {
+                packet = new DatagramPacket(buffer, buffer.length);
+                socket = new DatagramSocket(port, address);
+            } catch (IOException ex) {
+                throw new RuntimeException(
+                        "Creating datagram reflector failed", ex);
+            }
+        }
+    }
+
+    /**
+     * Converts a given datagram packet's contents to a String.
+     */
+    static String stringFromPacket(DatagramPacket packet) {
+        return new String(packet.getData(), 0, packet.getLength());
+    }
+
+    /**
+     * Converts a given String into a datagram packet.
+     */
+    static void stringToPacket(String s, DatagramPacket packet) {
+        byte[] bytes = s.getBytes();
+        System.arraycopy(bytes, 0, packet.getData(), 0, bytes.length);
+        packet.setLength(bytes.length);
+    }
+
+    /**
+     * Implements the main part of the Datagram test.
+     */
+    @LargeTest
+    public void testDatagram() throws Exception {
+
+        Reflector reflector = null;
+        DatagramSocket socket = null;
+
+        try {
+            // Setup the reflector, so we have a partner to send to
+            reflector = new Reflector(1234, InetAddress.getLocalHost());
+            reflector.start();
+
+            byte[] buffer = new byte[256];
+
+            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
+            socket = new DatagramSocket(2345, InetAddress.getLocalHost());
+
+            // Send ten simple packets and check for the expected responses.
+            for (int i = 1; i <= 10; i++) {
+                String s = "Hello, Android world #" + i + "!";
+                stringToPacket(s, packet);
+
+                packet.setAddress(InetAddress.getLocalHost());
+                packet.setPort(1234);
+
+                socket.send(packet);
+
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException ex) {
+                    // Ignore.
+                }
+
+                packet.setLength(buffer.length);
+                socket.receive(packet);
+                String t = stringFromPacket(packet);
+                // System.out.println(t + " (from " + packet.getAddress() + ":" + packet.getPort() + ")");
+
+                assertEquals(s.toUpperCase(), t);
+            }
+        } finally {
+            if (reflector != null) {
+                reflector.alive = false;
+            }
+
+            if (socket != null) {
+                socket.close();
+            }
+        }
+    }
+
+    // Regression test for issue 1018003: DatagramSocket ignored a set timeout.
+    @LargeTest
+    public void testDatagramSocketSetSOTimeout() throws Exception {
+        DatagramSocket sock = null;
+        int timeout = 5000;
+        long start = System.currentTimeMillis();
+        try {
+            sock = new DatagramSocket();
+            DatagramPacket pack = new DatagramPacket(new byte[100], 100);
+            sock.setSoTimeout(timeout);
+            sock.receive(pack);
+        } catch (SocketTimeoutException e) {
+            // expected
+            long delay = System.currentTimeMillis() - start;
+            if (Math.abs(delay - timeout) > 1000) {
+                fail("timeout was not accurate. expected: " + timeout
+                        + " actual: " + delay + " miliseconds.");
+            }
+        } finally {
+            if (sock != null) {
+                sock.close();
+            }
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/DeflateTest.java b/tests/CoreTests/android/core/DeflateTest.java
new file mode 100644
index 0000000..d68d697
--- /dev/null
+++ b/tests/CoreTests/android/core/DeflateTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.UnsupportedEncodingException;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class DeflateTest extends TestCase {
+
+    @LargeTest
+    public void testDeflate() throws Exception {
+        simpleTest();
+
+        bigTest(0, 1738149618);
+        bigTest(1, 934350518);
+        bigTest(2, -532869390);
+    }
+
+    /*
+     * Simple inflate/deflate test, taken from the reference docs for the
+     * Inflater/Deflater classes.
+     */
+    private void simpleTest()
+            throws UnsupportedEncodingException, DataFormatException {
+        // Encode a String into bytes
+        String inputString = "blahblahblah??";
+        byte[] input = inputString.getBytes("UTF-8");
+
+        // Compress the bytes
+        byte[] output = new byte[100];
+        Deflater compresser = new Deflater();
+        compresser.setInput(input);
+        compresser.finish();
+        int compressedDataLength = compresser.deflate(output);
+
+        // Decompress the bytes
+        Inflater decompresser = new Inflater();
+        decompresser.setInput(output, 0, compressedDataLength);
+        byte[] result = new byte[100];
+        int resultLength = decompresser.inflate(result);
+
+        // Decode the bytes into a String
+        String outputString = new String(result, 0, resultLength, "UTF-8");
+
+        assertEquals(inputString, outputString);
+        assertEquals(compresser.getAdler(), decompresser.getAdler());
+
+        decompresser.end();
+    }
+
+    /*
+     * "step" determines how compressible the data is.
+     *
+     * Note we must set "nowrap" to false, or the Adler-32 doesn't get
+     * computed.
+     */
+    private void bigTest(int step, int expectedAdler)
+            throws UnsupportedEncodingException, DataFormatException {
+        byte[] input = new byte[128 * 1024];
+        byte[] comp = new byte[128 * 1024 + 512];
+        byte[] output = new byte[128 * 1024 + 512];
+        Inflater inflater = new Inflater(false);
+        Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, false);
+
+        createSample(input, step);
+
+        compress(deflater, input, comp);
+        expand(inflater, comp, (int) deflater.getBytesWritten(), output);
+
+        assertEquals(inflater.getBytesWritten(), input.length);
+        assertEquals(deflater.getAdler(), inflater.getAdler());
+        assertEquals(deflater.getAdler(), expectedAdler);
+    }
+
+    /*
+     * Create a large data sample.
+     * stepStep = 0 --> >99% compression
+     * stepStep = 1 --> ~30% compression
+     * stepStep = 2 --> no compression
+     */
+    private void createSample(byte[] sample, int stepStep) {
+        byte val, step;
+        int i, j, offset;
+
+        assertTrue(sample.length >= 128 * 1024);
+
+        val = 0;
+        step = 1;
+        offset = 0;
+        for (i = 0; i < (128 * 1024) / 256; i++) {
+            for (j = 0; j < 256; j++) {
+                sample[offset++] = val;
+                val += step;
+            }
+
+            step += stepStep;
+        }
+    }
+
+    private static final int LOCAL_BUF_SIZE = 256;
+
+    /*
+     * Compress all data in "in" to "out".  We use a small window on input
+     * and output to exercise that part of the code.
+     *
+     * It's the caller's responsibility to ensure that "out" has enough
+     * space.
+     */
+    private void compress(Deflater deflater, byte[] inBuf, byte[] outBuf) {
+        int inCount = inBuf.length;        // use all
+        int inPosn;
+        int outPosn;
+
+        inPosn = outPosn = 0;
+
+        //System.out.println("### starting compress");
+
+        while (!deflater.finished()) {
+            int want = -1, got;
+
+            // only read if the input buffer is empty
+            if (deflater.needsInput() && inCount != 0) {
+                want = (inCount < LOCAL_BUF_SIZE) ? inCount : LOCAL_BUF_SIZE;
+
+                deflater.setInput(inBuf, inPosn, want);
+
+                inCount -= want;
+                inPosn += want;
+                if (inCount == 0) {
+                    deflater.finish();
+                }
+            }
+
+            // deflate to current position in output buffer
+            int compCount;
+
+            compCount = deflater.deflate(outBuf, outPosn, LOCAL_BUF_SIZE);
+            outPosn += compCount;
+
+            //System.out.println("Compressed " + want + ", output " + compCount);
+        }
+    }
+
+    /*
+     * Expand data from "inBuf" to "outBuf".  Uses a small window to better
+     * exercise the code.
+     */
+    private void expand(Inflater inflater, byte[] inBuf, int inCount,
+            byte[] outBuf) throws DataFormatException {
+        int inPosn;
+        int outPosn;
+
+        inPosn = outPosn = 0;
+
+        //System.out.println("### starting expand, inCount is " + inCount);
+
+        while (!inflater.finished()) {
+            int want = -1, got;
+
+            // only read if the input buffer is empty
+            if (inflater.needsInput() && inCount != 0) {
+                want = (inCount < LOCAL_BUF_SIZE) ? inCount : LOCAL_BUF_SIZE;
+
+                inflater.setInput(inBuf, inPosn, want);
+
+                inCount -= want;
+                inPosn += want;
+            }
+
+            // inflate to current position in output buffer
+            int compCount;
+
+            compCount = inflater.inflate(outBuf, outPosn, LOCAL_BUF_SIZE);
+            outPosn += compCount;
+
+            //System.out.println("Expanded " + want + ", output " + compCount);
+        }
+    }
+}
+
diff --git a/tests/CoreTests/android/core/EnumTest.java b/tests/CoreTests/android/core/EnumTest.java
new file mode 100644
index 0000000..d479491
--- /dev/null
+++ b/tests/CoreTests/android/core/EnumTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests basic behavior of enums.
+ */
+public class EnumTest extends TestCase {
+    enum MyEnum {
+        ZERO, ONE, TWO, THREE, FOUR {boolean isFour() {
+        return true;
+    }};
+
+        boolean isFour() {
+            return false;
+        }
+    }
+
+    enum MyEnumTwo {
+        FIVE, SIX
+    }
+
+    @SmallTest
+    public void testEnum() throws Exception {
+        assertTrue(MyEnum.ZERO.compareTo(MyEnum.ONE) < 0);
+        assertEquals(MyEnum.ZERO, MyEnum.ZERO);
+        assertTrue(MyEnum.TWO.compareTo(MyEnum.ONE) > 0);
+        assertTrue(MyEnum.FOUR.compareTo(MyEnum.ONE) > 0);
+
+        assertEquals("ONE", MyEnum.ONE.name());
+        assertSame(MyEnum.ONE.getDeclaringClass(), MyEnum.class);
+        assertSame(MyEnum.FOUR.getDeclaringClass(), MyEnum.class);
+
+        assertTrue(MyEnum.FOUR.isFour());
+
+        MyEnum e;
+
+        e = MyEnum.ZERO;
+
+        switch (e) {
+            case ZERO:
+                break;
+            default:
+                fail("wrong switch");
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/FileTest.java b/tests/CoreTests/android/core/FileTest.java
new file mode 100644
index 0000000..980452e
--- /dev/null
+++ b/tests/CoreTests/android/core/FileTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Checks creation and deletion of a file.
+ */
+public class FileTest extends TestCase {
+
+    @SmallTest
+    public void testFile() throws Exception {
+
+        File file = File.createTempFile(String.valueOf(System.currentTimeMillis()), null, null);
+
+        assertTrue(file.exists());
+        assertTrue(file.delete());
+        assertFalse(file.exists());
+    }
+}
diff --git a/tests/CoreTests/android/core/FloatDoubleTest.java b/tests/CoreTests/android/core/FloatDoubleTest.java
new file mode 100644
index 0000000..8c8455b
--- /dev/null
+++ b/tests/CoreTests/android/core/FloatDoubleTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for basic functionality of floats and doubles.
+ */
+public class FloatDoubleTest extends TestCase {
+
+    @SmallTest
+    public void testFloatDouble() throws Exception {
+        Double d = Double.valueOf(1.0);
+        Float f = Float.valueOf(1.0f);
+        Object o = new Object();
+
+        assertFalse(f.equals(d));
+        assertFalse(d.equals(f));
+        assertFalse(f.equals(o));
+        assertFalse(d.equals(o));
+        assertFalse(f.equals(null));
+        assertFalse(d.equals(null));
+    }
+
+    @SmallTest
+    public void testFloat() throws Exception {
+        float pz = 0.0f;
+        float nz = -0.0f;
+
+        float pzero = 1.0f / Float.POSITIVE_INFINITY;
+        float nzero = 1.0f / Float.NEGATIVE_INFINITY;
+
+        // Everything compares as '=='
+        assertTrue(pz == pz);
+        assertTrue(pz == nz);
+        assertTrue(pz == pzero);
+        assertTrue(pz == nzero);
+
+        assertTrue(nz == pz);
+        assertTrue(nz == nz);
+        assertTrue(nz == pzero);
+        assertTrue(nz == nzero);
+
+        assertTrue(pzero == pz);
+        assertTrue(pzero == nz);
+        assertTrue(pzero == pzero);
+        assertTrue(pzero == nzero);
+
+        assertTrue(nzero == pz);
+        assertTrue(nzero == nz);
+        assertTrue(nzero == pzero);
+        assertTrue(nzero == nzero);
+
+        // +-0 are distinct as Floats
+        assertEquals(Float.valueOf(pz), Float.valueOf(pz));
+        assertTrue(!Float.valueOf(pz).equals(Float.valueOf(nz)));
+        assertEquals(Float.valueOf(pz), Float.valueOf(pzero));
+        assertTrue(!Float.valueOf(pz).equals(Float.valueOf(nzero)));
+
+        assertTrue(!Float.valueOf(nz).equals(Float.valueOf(pz)));
+        assertEquals(Float.valueOf(nz), Float.valueOf(nz));
+        assertTrue(!Float.valueOf(nz).equals(Float.valueOf(pzero)));
+        assertEquals(Float.valueOf(nz), Float.valueOf(nzero));
+
+        assertEquals(Float.valueOf(pzero), Float.valueOf(pz));
+        assertTrue(!Float.valueOf(pzero).equals(Float.valueOf(nz)));
+        assertEquals(Float.valueOf(pzero), Float.valueOf(pzero));
+        assertTrue(!Float.valueOf(pzero).equals(Float.valueOf(nzero)));
+
+        assertTrue(!Float.valueOf(nzero).equals(Float.valueOf(pz)));
+        assertEquals(Float.valueOf(nzero), Float.valueOf(nz));
+        assertTrue(!Float.valueOf(nzero).equals(Float.valueOf(pzero)));
+        assertEquals(Float.valueOf(nzero), Float.valueOf(nzero));
+
+        // Nan's compare as equal
+        Float sqrtm2 = Float.valueOf((float) Math.sqrt(-2.0f));
+        Float sqrtm3 = Float.valueOf((float) Math.sqrt(-3.0f));
+        assertEquals(sqrtm2, sqrtm3);
+    }
+
+    @SmallTest
+    public void testDouble() throws Exception {
+        double pz = 0.0;
+        double nz = -0.0;
+
+        double pzero = 1.0 / Double.POSITIVE_INFINITY;
+        double nzero = 1.0 / Double.NEGATIVE_INFINITY;
+
+        // Everything compares as '=='
+        assertTrue(pz == pz);
+        assertTrue(pz == nz);
+        assertTrue(pz == pzero);
+        assertTrue(pz == nzero);
+
+        assertTrue(nz == pz);
+        assertTrue(nz == nz);
+        assertTrue(nz == pzero);
+        assertTrue(nz == nzero);
+
+        assertTrue(pzero == pz);
+        assertTrue(pzero == nz);
+        assertTrue(pzero == pzero);
+        assertTrue(pzero == nzero);
+
+        assertTrue(nzero == pz);
+        assertTrue(nzero == nz);
+        assertTrue(nzero == pzero);
+        assertTrue(nzero == nzero);
+
+        // +-0 are distinct as Doubles
+        assertEquals(Double.valueOf(pz), Double.valueOf(pz));
+        assertTrue(!Double.valueOf(pz).equals(Double.valueOf(nz)));
+        assertEquals(Double.valueOf(pz), Double.valueOf(pzero));
+        assertTrue(!Double.valueOf(pz).equals(Double.valueOf(nzero)));
+
+        assertTrue(!Double.valueOf(nz).equals(Double.valueOf(pz)));
+        assertEquals(Double.valueOf(nz), Double.valueOf(nz));
+        assertTrue(!Double.valueOf(nz).equals(Double.valueOf(pzero)));
+        assertEquals(Double.valueOf(nz), Double.valueOf(nzero));
+
+        assertEquals(Double.valueOf(pzero), Double.valueOf(pz));
+        assertTrue(!Double.valueOf(pzero).equals(Double.valueOf(nz)));
+        assertEquals(Double.valueOf(pzero), Double.valueOf(pzero));
+        assertTrue(!Double.valueOf(pzero).equals(Double.valueOf(nzero)));
+
+        assertTrue(!Double.valueOf(nzero).equals(Double.valueOf(pz)));
+        assertEquals(Double.valueOf(nzero), Double.valueOf(nz));
+        assertTrue(!Double.valueOf(nzero).equals(Double.valueOf(pzero)));
+        assertEquals(Double.valueOf(nzero), Double.valueOf(nzero));
+
+        // Nan's compare as equal
+        Double sqrtm2 = Double.valueOf(Math.sqrt(-2.0));
+        Double sqrtm3 = Double.valueOf(Math.sqrt(-3.0));
+        assertEquals(sqrtm2, sqrtm3);
+    }
+}
diff --git a/tests/CoreTests/android/core/GZIPStreamTest.java b/tests/CoreTests/android/core/GZIPStreamTest.java
new file mode 100644
index 0000000..dd56fb7
--- /dev/null
+++ b/tests/CoreTests/android/core/GZIPStreamTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Deflates and inflates some test data with GZipStreams
+ */
+public class GZIPStreamTest extends TestCase {
+
+    @MediumTest
+    public void testGZIPStream() throws Exception {
+        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+        createGZIP(bytesOut);
+
+        byte[] zipData;
+        zipData = bytesOut.toByteArray();
+
+        /*
+        FileOutputStream outFile = new FileOutputStream("/tmp/foo.gz");
+        outFile.write(zipData, 0, zipData.length);
+        outFile.close();
+        */
+
+        /*
+        FileInputStream inFile = new FileInputStream("/tmp/foo.gz");
+        int inputLength = inFile.available();
+        zipData = new byte[inputLength];
+        if (inFile.read(zipData) != inputLength)
+            throw new RuntimeException();
+        inFile.close();
+        */
+
+        ByteArrayInputStream bytesIn = new ByteArrayInputStream(zipData);
+        scanGZIP(bytesIn);
+    }
+
+    /*
+     * stepStep == 0 --> >99% compression
+     * stepStep == 1 --> ~30% compression
+     * stepStep == 2 --> no compression
+     */
+    static byte[] makeSampleFile(int stepStep) throws IOException {
+        byte[] sample = new byte[128 * 1024];
+        byte val, step;
+        int i, j, offset;
+
+        val = 0;
+        step = 1;
+        offset = 0;
+        for (i = 0; i < (128 * 1024) / 256; i++) {
+            for (j = 0; j < 256; j++) {
+                sample[offset++] = val;
+                val += step;
+            }
+
+            step += stepStep;
+        }
+
+        return sample;
+    }
+
+    static void createGZIP(ByteArrayOutputStream bytesOut) throws IOException {
+        GZIPOutputStream out = new GZIPOutputStream(bytesOut);
+        try {
+            byte[] input = makeSampleFile(1);
+            out.write(input, 0, input.length);
+            //out.finish();
+        } finally {
+            out.close();
+        }
+    }
+
+    static void scanGZIP(ByteArrayInputStream bytesIn) throws IOException {
+        GZIPInputStream in = new GZIPInputStream(bytesIn);
+        try {
+            ByteArrayOutputStream contents = new ByteArrayOutputStream();
+            byte[] buf = new byte[4096];
+            int len, totalLen = 0;
+
+            while ((len = in.read(buf)) > 0) {
+                contents.write(buf, 0, len);
+                totalLen += len;
+            }
+
+            assertEquals(totalLen, 128 * 1024);
+        } finally {
+            in.close();
+        }
+    }
+}
+
diff --git a/tests/CoreTests/android/core/HashMapPerfTest.java b/tests/CoreTests/android/core/HashMapPerfTest.java
new file mode 100644
index 0000000..8475222
--- /dev/null
+++ b/tests/CoreTests/android/core/HashMapPerfTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.LargeTest;
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Random;
+
+/**
+ * Tests basic functionality of HashMaps and prints the time needed to System.out
+ */
+public class HashMapPerfTest extends TestCase {
+
+    private static final Random sRandom = new Random(1);
+
+    class StringThing {
+
+        String mId;
+
+        public StringThing() {
+            int len = sRandom.nextInt(20) + 1;
+            char[] chars = new char[len];
+            chars[0] = 't';
+            for (int i = 1; i < len; i++) {
+                chars[i] = (char) ('q' + sRandom.nextInt(4));
+            }
+            mId = new String(chars, 0, len);
+        }
+
+        public String getId() {
+            return mId;
+        }
+    }
+
+    private static final int NUM_ELTS = 1000;
+    private static final int ITERS = 100;
+
+    String[] keyCopies = new String[NUM_ELTS];
+
+    private static final boolean lookupByOriginals = false;
+
+    @LargeTest
+    public void testHashMapPerformance() throws Exception {
+        StringThing[] st = new StringThing[NUM_ELTS];
+        for (int i = 0; i < NUM_ELTS; i++) {
+            st[i] = new StringThing();
+            keyCopies[i] = st[i].getId();
+        }
+
+        // android.os.Debug.startMethodTracing();
+        long start = SystemClock.uptimeMillis();
+        for (int i = 0; i < ITERS; i++) {
+            HashMap<String, StringThing> map = new HashMap<String, StringThing>();
+            for (int j = 0; j < NUM_ELTS; j++) {
+                StringThing s = st[i];
+                map.put(s.getId(), s);
+            }
+            for (int j = 0; j < NUM_ELTS; j++) {
+                if (lookupByOriginals) {
+                    StringThing s = st[i];
+                    map.get(s.getId());
+                } else {
+                    map.get(keyCopies[j]);
+                }
+            }
+        }
+        long finish = SystemClock.uptimeMillis();
+        // android.os.Debug.stopMethodTracing();
+
+        // This should be an assertion instead
+        
+//        System.out.println("time (" + NUM_ELTS +
+//                ", elts, " + ITERS +
+//                " iters) = " + (finish - start));
+    }
+}
diff --git a/tests/CoreTests/android/core/HashMapTest.java b/tests/CoreTests/android/core/HashMapTest.java
new file mode 100644
index 0000000..99b2a47
--- /dev/null
+++ b/tests/CoreTests/android/core/HashMapTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Test cases for Hashmap.
+ */
+public class HashMapTest extends TestCase {
+    private static final Integer ONE = new Integer(1);
+    private static final Integer TWO = new Integer(2);
+    private static final Integer THREE = new Integer(3);
+    private static final Integer FOUR = new Integer(4);
+
+    private void addItems(HashMap map) {
+        map.put("one", ONE);
+        map.put("two", TWO);
+        map.put("three", THREE);
+        map.put("four", FOUR);
+
+        assertEquals(4, map.size());
+
+        assertEquals(ONE, map.get("one"));
+        assertEquals(TWO, map.get("two"));
+        assertEquals(THREE, map.get("three"));
+        assertEquals(FOUR, map.get("four"));
+    }
+
+    /**
+     * checks if simple adding elements works.
+     */
+    @SmallTest
+    public void testAdd() throws Exception {
+        HashMap map = new HashMap();
+        addItems(map);
+    }
+
+    /**
+     * checks if clearing the map works.
+     */
+    @SmallTest
+    public void testClear() throws Exception {
+        HashMap map = new HashMap();
+
+        addItems(map);
+        map.clear();
+        assertEquals(0, map.size());
+    }
+
+    /**
+     * checks if removing an elemt works.
+     */
+    @SmallTest
+    public void testRemove() throws Exception {
+        HashMap map = new HashMap();
+
+        addItems(map);
+        map.remove("three");
+        assertNull(map.get("three"));
+    }
+
+    /**
+     * does some manipulation with a filled HashMap and checks
+     * if they work as intended
+     */
+    @SmallTest
+    public void testManipulate() throws Exception {
+        HashMap map = new HashMap();
+
+        assertTrue(map.isEmpty());
+        assertEquals(0, map.size());
+        assertNull(map.get(null));
+        assertNull(map.get("one"));
+        assertFalse(map.containsKey("one"));
+        assertFalse(map.containsValue(new Integer(1)));
+        assertNull(map.remove(null));
+        assertNull(map.remove("one"));
+
+        assertNull(map.put(null, new Integer(-1)));
+        assertNull(map.put("one", new Integer(1)));
+        assertNull(map.put("two", new Integer(2)));
+        assertNull(map.put("three", new Integer(3)));
+        assertEquals(-1, ((Integer) map.put(null, new Integer(0))).intValue());
+
+        assertEquals(0, ((Integer) map.get(null)).intValue());
+        assertEquals(1, ((Integer) map.get("one")).intValue());
+        assertEquals(2, ((Integer) map.get("two")).intValue());
+        assertEquals(3, ((Integer) map.get("three")).intValue());
+
+        assertTrue(map.containsKey(null));
+        assertTrue(map.containsKey("one"));
+        assertTrue(map.containsKey("two"));
+        assertTrue(map.containsKey("three"));
+
+        assertTrue(map.containsValue(new Integer(0)));
+        assertTrue(map.containsValue(new Integer(1)));
+        assertTrue(map.containsValue(new Integer(2)));
+        assertTrue(map.containsValue(new Integer(3)));
+
+        assertEquals(0, ((Integer) map.remove(null)).intValue());
+        assertEquals(1, ((Integer) map.remove("one")).intValue());
+        assertEquals(2, ((Integer) map.remove("two")).intValue());
+        assertEquals(3, ((Integer) map.remove("three")).intValue());
+
+        assertTrue(map.isEmpty());
+        assertEquals(0, map.size());
+        assertNull(map.get(null));
+        assertNull(map.get("one"));
+        assertFalse(map.containsKey("one"));
+        assertFalse(map.containsValue(new Integer(1)));
+        assertNull(map.remove(null));
+        assertNull(map.remove("one"));
+    }
+
+    /**
+     * checks if the key iterator of HashMaps work.
+     */
+    @SmallTest
+    public void testKeyIterator() throws Exception {
+        HashMap map = new HashMap();
+
+        boolean[] slots = new boolean[4];
+
+        addItems(map);
+
+        Iterator iter = map.keySet().iterator();
+
+        while (iter.hasNext()) {
+            int slot = 0;
+            Object key = iter.next();
+
+            if (key.equals("one"))
+                slot = 0;
+            else if (key.equals("two"))
+                slot = 1;
+            else if (key.equals("three"))
+                slot = 2;
+            else if (key.equals("four"))
+                slot = 3;
+            else
+                fail("Unkown key in hashmap");
+
+            if (slots[slot])
+                fail("key returned more than once");
+            else
+                slots[slot] = true;
+        }
+
+        assertTrue(slots[0]);
+        assertTrue(slots[1]);
+        assertTrue(slots[2]);
+        assertTrue(slots[3]);
+    }
+
+    /**
+     * checks if the value iterator works.
+     */
+    @SmallTest
+    public void testValueIterator() throws Exception {
+        HashMap map = new HashMap();
+
+        boolean[] slots = new boolean[4];
+
+        addItems(map);
+
+        Iterator iter = map.values().iterator();
+
+        while (iter.hasNext()) {
+            int slot = 0;
+            Object value = iter.next();
+
+            if (value.equals(ONE))
+                slot = 0;
+            else if (value.equals(TWO))
+                slot = 1;
+            else if (value.equals(THREE))
+                slot = 2;
+            else if (value.equals(FOUR))
+                slot = 3;
+            else
+                fail("Unkown value in hashmap");
+
+            if (slots[slot])
+                fail("value returned more than once");
+            else
+                slots[slot] = true;
+        }
+
+        assertTrue(slots[0]);
+        assertTrue(slots[1]);
+        assertTrue(slots[2]);
+        assertTrue(slots[3]);
+    }
+
+    /**
+     * checks if the entry iterator works for HashMaps.
+     */
+    @SmallTest
+    public void testEntryIterator() throws Exception {
+        HashMap map = new HashMap();
+
+        boolean[] slots = new boolean[4];
+
+        addItems(map);
+
+        Iterator iter = map.entrySet().iterator();
+
+        while (iter.hasNext()) {
+            int slot = 0;
+            Object entry = iter.next();
+
+            if (entry.toString().equals("one=1"))
+                slot = 0;
+            else if (entry.toString().equals("two=2"))
+                slot = 1;
+            else if (entry.toString().equals("three=3"))
+                slot = 2;
+            else if (entry.toString().equals("four=4"))
+                slot = 3;
+            else
+                fail("Unkown entry in hashmap");
+
+            if (slots[slot])
+                fail("entry returned more than once");
+            else
+                slots[slot] = true;
+        }
+
+        assertTrue(slots[0]);
+        assertTrue(slots[1]);
+        assertTrue(slots[2]);
+        assertTrue(slots[3]);
+    }
+
+    /**
+     * checks if the HashMap equals method works.
+     */
+    @SmallTest
+    public void testEquals() throws Exception {
+        HashMap map1 = new HashMap();
+        HashMap map2 = new HashMap();
+        HashMap map3 = new HashMap();
+
+        map1.put("one", "1");
+        map1.put("two", "2");
+        map1.put("three", "3");
+
+        map2.put("one", new String("1"));
+        map2.put(new String("two"), "2");
+        map2.put(new String("three"), new String("3"));
+
+        assertTrue(map1.equals(map2));
+
+        map3.put("one", "1");
+        map3.put("two", "1");
+        map3.put("three", "1");
+
+        assertFalse(map1.equals(map3));
+        assertFalse(map2.equals(map3));
+    }
+}
+
diff --git a/tests/CoreTests/android/core/HttpConstants.java b/tests/CoreTests/android/core/HttpConstants.java
new file mode 100644
index 0000000..d655d52
--- /dev/null
+++ b/tests/CoreTests/android/core/HttpConstants.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+interface HttpConstants {
+    /** 2XX: generally "OK" */
+    public static final int HTTP_OK = 200;
+    public static final int HTTP_CREATED = 201;
+    public static final int HTTP_ACCEPTED = 202;
+    public static final int HTTP_NOT_AUTHORITATIVE = 203;
+    public static final int HTTP_NO_CONTENT = 204;
+    public static final int HTTP_RESET = 205;
+    public static final int HTTP_PARTIAL = 206;
+
+    /** 3XX: relocation/redirect */
+    public static final int HTTP_MULT_CHOICE = 300;
+    public static final int HTTP_MOVED_PERM = 301;
+    public static final int HTTP_MOVED_TEMP = 302;
+    public static final int HTTP_SEE_OTHER = 303;
+    public static final int HTTP_NOT_MODIFIED = 304;
+    public static final int HTTP_USE_PROXY = 305;
+
+    /** 4XX: client error */
+    public static final int HTTP_BAD_REQUEST = 400;
+    public static final int HTTP_UNAUTHORIZED = 401;
+    public static final int HTTP_PAYMENT_REQUIRED = 402;
+    public static final int HTTP_FORBIDDEN = 403;
+    public static final int HTTP_NOT_FOUND = 404;
+    public static final int HTTP_BAD_METHOD = 405;
+    public static final int HTTP_NOT_ACCEPTABLE = 406;
+    public static final int HTTP_PROXY_AUTH = 407;
+    public static final int HTTP_CLIENT_TIMEOUT = 408;
+    public static final int HTTP_CONFLICT = 409;
+    public static final int HTTP_GONE = 410;
+    public static final int HTTP_LENGTH_REQUIRED = 411;
+    public static final int HTTP_PRECON_FAILED = 412;
+    public static final int HTTP_ENTITY_TOO_LARGE = 413;
+    public static final int HTTP_REQ_TOO_LONG = 414;
+    public static final int HTTP_UNSUPPORTED_TYPE = 415;
+
+    /** 5XX: server error */
+    public static final int HTTP_SERVER_ERROR = 500;
+    public static final int HTTP_INTERNAL_ERROR = 501;
+    public static final int HTTP_BAD_GATEWAY = 502;
+    public static final int HTTP_UNAVAILABLE = 503;
+    public static final int HTTP_GATEWAY_TIMEOUT = 504;
+    public static final int HTTP_VERSION = 505;
+
+    /** Method IDs */
+    public static final int UNKNOWN_METHOD = 0;
+    public static final int GET_METHOD = 1;
+    public static final int HEAD_METHOD = 2;
+    public static final int POST_METHOD = 3;
+
+    public static final String[] requestHeaders = {
+        "cache-control",
+        "connection",
+        "date",
+        "pragma",
+        "trailer",
+        "transfer-encoding",
+        "upgrade",
+        "via",
+        "warning",
+        "accept",
+        "accept-charset",
+        "accept-encoding",
+        "accept-language",
+        "authorization",
+        "expect",
+        "from",
+        "host",
+        "if-match",
+        "if-modified-since",
+        "if-none-match",
+        "if-range",
+        "if-unmodified-since",
+        "max-forwards",
+        "proxy-authentication",
+        "range",
+        "referer",
+        "te",
+        "user-agent",
+        "keep-alive",
+        "allow",
+        "content-encoding",
+        "content-language",
+        "content-length",
+        "content-location",
+        "content-md5",
+        "content-range",
+        "content-type",
+        "expires",
+        "last-modified",
+        "location",
+        "server"
+
+    };
+
+    public static final int REQ_UNKNOWN = -1;
+    public static final int REQ_CACHE_CONTROL = 0;
+    public static final int REQ_CONNECTION = 1;
+    public static final int REQ_DATE = 2;
+    public static final int REQ_PRAGMA = 3;
+    public static final int REQ_TRAILER = 4;
+    public static final int REQ_TRANSFER_ENCODING = 5;
+    public static final int REQ_UPGRADE = 6;
+    public static final int REQ_VIA = 7;
+    public static final int REQ_WARNING = 8;
+    public static final int REQ_ACCEPT = 9;
+    public static final int REQ_ACCEPT_CHARSET = 10;
+    public static final int REQ_ACCEPT_ENCODING = 11;
+    public static final int REQ_ACCEPT_LANGUAGE = 12;
+    public static final int REQ_AUTHORIZATION = 13;
+    public static final int REQ_EXPECT = 14;
+    public static final int REQ_FROM = 15;
+    public static final int REQ_HOST = 16;
+    public static final int REQ_IF_MATCH = 17;
+    public static final int REQ_IF_MODIFIED_SINCE = 18;
+    public static final int REQ_IF_NONE_MATCH = 19;
+    public static final int REQ_IF_RANGE = 20;
+    public static final int REQ_IF_UNMODIFIED_SINCE = 21;
+    public static final int REQ_MAX_FORWARDS = 22;
+    public static final int REQ_PROXY_AUTHENTICATION = 23;
+    public static final int REQ_RANGE = 24;
+    public static final int REQ_REFERER = 25;
+    public static final int REQ_TE = 26;
+    public static final int REQ_USER_AGENT = 27;
+    public static final int REQ_KEEP_ALIVE = 28;
+    public static final int REQ_ALLOW = 29;
+    public static final int REQ_CONTENT_ENCODING = 30;
+    public static final int REQ_CONTENT_LANGUAGE = 31;
+    public static final int REQ_CONTENT_LENGTH = 32;
+    public static final int REQ_CONTENT_LOCATION = 33;
+    public static final int REQ_CONTENT_MD5 = 34;
+    public static final int REQ_CONTENT_RANGE = 35;
+    public static final int REQ_CONTENT_TYPE = 36;
+    public static final int REQ_EXPIRES = 37;
+    public static final int REQ_LAST_MODIFIED = 38;
+    public static final int REQ_LOCATION = 39;
+    public static final int REQ_SERVER = 40;
+
+}
diff --git a/tests/CoreTests/android/core/IOUtil.java b/tests/CoreTests/android/core/IOUtil.java
new file mode 100644
index 0000000..6f69418
--- /dev/null
+++ b/tests/CoreTests/android/core/IOUtil.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.InputStreamReader;
+
+public final class IOUtil {
+
+    private IOUtil() {
+    }
+
+    /**
+     * returns the content of an InputStream as a String.
+     *
+     * @param a the input stream.
+     * @return the string
+     * @throws java.io.IOException
+     */
+    public static String read(InputStream a) throws IOException {
+        int r;
+        StringBuilder builder = new StringBuilder();
+        do {
+            r = a.read();
+            if (r != -1)
+                builder.append((char) r);
+        } while (r != -1);
+        return builder.toString();
+    }
+
+    /**
+     * reads characters from a reader and returns them as a string.
+     *
+     * @param a the reader.
+     * @return the string.
+     * @throws IOException
+     */
+    public static String read(Reader a) throws IOException {
+        int r;
+        StringBuilder builder = new StringBuilder();
+        do {
+            r = a.read();
+            if (r != -1)
+                builder.append((char) r);
+        } while (r != -1);
+        return builder.toString();
+    }
+
+    /**
+     * returns the content of an InputStream as a String. It reads x characters.
+     *
+     * @param a the input stream.
+     * @param x number of characters to read.
+     * @return the string
+     * @throws IOException
+     */
+    public static String read(InputStream a, int x) throws IOException {
+        byte[] b = new byte[x];
+        int len = a.read(b, 0, x);
+        if (len < 0) {
+            return "";
+        }
+        return new String(b, 0, len);
+    }
+
+    /**
+     * reads a number of characters from a reader and returns them as a string.
+     *
+     * @param a the reader.
+     * @param x the number of characters to read.
+     * @return the string.
+     * @throws IOException
+     */
+    public static String read(Reader a, int x) throws IOException {
+        char[] b = new char[x];
+        int len = a.read(b, 0, x);
+        if (len < 0) {
+            return "";
+        }
+        return new String(b, 0, len);
+    }
+
+    /**
+     * returns the content of the input stream as a String. It only appends
+     * every second character.
+     *
+     * @param a the input stream.
+     * @return the string created from every second character of the input stream.
+     * @throws IOException
+     */
+    public static String skipRead(InputStream a) throws IOException {
+        int r;
+        StringBuilder builder = new StringBuilder();
+        do {
+            a.skip(1);
+            r = a.read();
+            if (r != -1)
+                builder.append((char) r);
+        } while (r != -1);
+        return builder.toString();
+    }
+
+    /**
+     * reads every second characters from a reader and returns them as a string.
+     *
+     * @param a the reader.
+     * @return the string.
+     * @throws IOException
+     */
+    public static String skipRead(Reader a) throws IOException {
+        int r;
+        StringBuilder builder = new StringBuilder();
+        do {
+            a.skip(1);
+            r = a.read();
+            if (r != -1)
+                builder.append((char) r);
+        } while (r != -1);
+        return builder.toString();
+    }
+
+    /**
+     * reads characters from a InputStream, skips back y characters and continues
+     * reading from that new position up to the end.
+     *
+     * @param a the InputStream.
+     * @param x the position of the mark. the marks position is x+y
+     * @param y the number of characters to jump back after the position x+y was reached.
+     * @return the string.
+     * @throws IOException
+     */
+    public static String markRead(InputStream a, int x, int y) throws IOException {
+        int m = 0;
+        int r;
+        StringBuilder builder = new StringBuilder();
+        do {
+            m++;
+            r = a.read();
+            if (m == x)
+                a.mark((x + y));
+            if (m == (x + y))
+                a.reset();
+
+            if (r != -1)
+                builder.append((char) r);
+        } while (r != -1);
+        return builder.toString();
+    }
+
+    /**
+     * reads characters from a reader, skips back y characters and continues
+     * reading from that new position up to the end.
+     *
+     * @param a the reader.
+     * @param x the position of the mark. the marks position is x+y
+     * @param y the number of characters to jump back after the position x+y was reached.
+     * @return the string.
+     * @throws IOException
+     */
+    public static String markRead(Reader a, int x, int y) throws IOException {
+        int m = 0;
+        int r;
+        StringBuilder builder = new StringBuilder();
+        do {
+            m++;
+            r = a.read();
+            if (m == x)
+                a.mark((x + y));
+            if (m == (x + y))
+                a.reset();
+
+            if (r != -1)
+                builder.append((char) r);
+        } while (r != -1);
+        return builder.toString();
+    }
+}
diff --git a/tests/CoreTests/android/core/InetAddrTest.java b/tests/CoreTests/android/core/InetAddrTest.java
new file mode 100644
index 0000000..c7b89e1
--- /dev/null
+++ b/tests/CoreTests/android/core/InetAddrTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Random;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Tests InetAddr class by checking methods to resolve domains to IP addresses
+ * and by checking if the class returns correct addresses for local host address
+ * and host name.
+ */
+@Suppress
+public class InetAddrTest extends TestCase {
+    private static final String[] HOSTS = {
+            "localhost", "www.google.com", "www.slashdot.org", "www.wikipedia.org",
+            "www.paypal.com", "www.cnn.com", "www.yahoo.com", "www.amazon.com",
+            "www.ebay.com", "www.android.com"
+    };
+
+    public void testInetAddr() throws Exception {
+        byte[] raw;
+
+        InetAddress ia = InetAddress.getByName("localhost");
+
+        raw = ia.getAddress();
+
+        assertEquals(127, raw[0]);
+        assertEquals(0, raw[1]);
+        assertEquals(0, raw[2]);
+        assertEquals(1, raw[3]);
+
+        ia = InetAddress.getByName("127.0.0.1");
+
+        raw = ia.getAddress();
+
+        assertEquals(127, raw[0]);
+        assertEquals(0, raw[1]);
+        assertEquals(0, raw[2]);
+        assertEquals(1, raw[3]);
+
+        ia = InetAddress.getByName(null);
+
+        try {
+            InetAddress.getByName(".0.0.1");
+            fail("expected ex");
+        } catch (UnknownHostException ex) {
+            // expected
+        }
+
+        try {
+            InetAddress.getByName("thereisagoodchancethisdomaindoesnotexist.weirdtld");
+            fail("expected ex");
+        } catch (UnknownHostException ex) {
+            // expected
+        }
+
+        try {
+            InetAddress.getByName("127.0.0.");
+            fail("expected ex");
+        } catch (UnknownHostException ex) {
+            // expected
+        }
+
+        Random random = new Random();
+        int count = 0;
+        for (int i = 0; i < 100; i++) {
+            int index = random.nextInt(HOSTS.length);
+            try {
+                InetAddress.getByName(HOSTS[index]);
+                count++;
+                try {
+                    Thread.sleep(50);
+                } catch (InterruptedException ex) {
+                }
+            } catch (UnknownHostException ex) {
+            }
+        }
+        assertEquals("Not all host lookups succeeded", 100, count);
+    }
+}
diff --git a/tests/CoreTests/android/core/InputStreamReaderTest.java b/tests/CoreTests/android/core/InputStreamReaderTest.java
new file mode 100644
index 0000000..1e8d87c
--- /dev/null
+++ b/tests/CoreTests/android/core/InputStreamReaderTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Checks basic InputStreamReader functionality.
+ */
+public class InputStreamReaderTest extends TestCase {
+
+    /**
+     * Checks if ASCII encoding works with InputStreamReader
+     */
+    @SmallTest
+    public void testAscii() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYzX";
+        ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes("ISO8859_1"));
+        InputStreamReader a = new InputStreamReader(aa, "ISO8859_1");
+
+        try {
+            int x = a.read();
+            assertEquals('A', x);
+            char[] c = new char[26];
+            x = a.read(c, 0, 26);
+            assertTrue(a.getEncoding().equalsIgnoreCase("ISO8859_1"));
+            assertEquals(26, x);
+            assertEquals("bCdEfGhIjKlMnOpQrStUvWxYzX", String.valueOf(c));
+        } finally {
+            a.close();
+        }
+    }
+
+    /**
+     * Checks if Utf8 encoding works with InputStreamReader
+     */
+    @SmallTest
+    public void testUtf8() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYzX" +
+                "\u00a3\u00c5\u00c9";       // total of 30 characters
+        ByteArrayInputStream aa =
+                new ByteArrayInputStream(str.getBytes());
+
+        InputStreamReader a = new InputStreamReader(aa);
+
+        try {
+            assertEquals("UTF8", a.getEncoding());
+
+            int x = a.read();
+            assertEquals('A', x);
+
+            char[] c = new char[29];
+            x = a.read(c, 0, 3);
+            assertEquals(3, x);
+            assertEquals("bCd", new String(c, 0, 3));
+
+            x = a.read(c, 3, 26);
+            assertEquals(26, x);
+            assertEquals("EfGhIjKlMnOpQrStUvWxYzX\u00a3\u00c5\u00c9", new String(c, 3, 26));
+        } finally {
+            a.close();
+        }
+    }
+
+    /**
+     * Checks if several encodings works with InputStreamReader
+     */
+    @SmallTest
+    public void testStringy() throws Exception {
+        String src = "The quick brown fox\u00A0\u00FF" +
+                "\uFFFC\uD7C5\uDC03bloof";
+
+        String[] enc = new String[]{
+                "utf-8", "us-ascii", "iso-8859-1", "utf-16be", "utf-16le",
+                "utf-16",
+        };
+
+        for (int i = 0; i < enc.length; i++) {
+            byte[] ba = src.getBytes(enc[i]);
+
+            String s1 = new String(ba, enc[i]);
+
+            ByteArrayInputStream bais = new ByteArrayInputStream(ba);
+            InputStreamReader r = new InputStreamReader(bais, enc[i]);
+            try {
+                char[] ca = new char[600];
+                int n = r.read(ca, 0, 600);
+
+                String s2 = new String(ca, 0, n);
+                assertEquals(s1, s2);
+            } finally {
+                r.close();
+            }
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/JavaTests.java b/tests/CoreTests/android/core/JavaTests.java
new file mode 100644
index 0000000..bd8cbf0
--- /dev/null
+++ b/tests/CoreTests/android/core/JavaTests.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestSuite;
+
+public class JavaTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(JavaTests.class.getName());
+
+        //Disabling until bug http://b/issue?id=1200337 is resolved
+        //suite.addTestSuite(RequestAPITest.class);
+        suite.addTestSuite(MathTest.class);
+        suite.addTestSuite(StrictMathTest.class);
+        suite.addTestSuite(HashMapPerfTest.class);
+        suite.addTestSuite(TreeMapTest.class);
+        suite.addTestSuite(FloatDoubleTest.class);
+        suite.addTestSuite(Sha1Test.class);
+        suite.addTestSuite(NIOTest.class);
+        suite.addTestSuite(ReflectArrayTest.class);
+        //Commenting out until we find a better way to exclude from continuous testing.
+        //suite.addTestSuite(URLTest.class);
+        suite.addTestSuite(URITest.class);
+        suite.addTestSuite(RegexTest.class);
+        suite.addTestSuite(HashMapTest.class);
+        suite.addTestSuite(ArrayListTest.class);
+        suite.addTestSuite(BooleanTest.class);
+        suite.addTestSuite(StringTest.class);
+        suite.addTestSuite(BufferedReaderTest.class);
+        suite.addTestSuite(CharArrayReaderTest.class);
+        suite.addTestSuite(PushbackReaderTest.class);
+        suite.addTestSuite(StringReaderTest.class);
+        suite.addTestSuite(StreamTokenizerTest.class);
+        suite.addTestSuite(ByteArrayInputStreamTest.class);
+        suite.addTestSuite(DataInputStreamTest.class);
+        suite.addTestSuite(BufferedInputStreamTest.class);
+        suite.addTestSuite(PushbackInputStreamTest.class);
+        suite.addTestSuite(ByteArrayOutputStreamTest.class);
+        suite.addTestSuite(DataOutputStreamTest.class);
+        suite.addTestSuite(BufferedOutputStreamTest.class);
+        suite.addTestSuite(CharArrayWriterTest.class);
+        suite.addTestSuite(StringWriterTest.class);
+        suite.addTestSuite(PrintWriterTest.class);
+        suite.addTestSuite(BufferedWriterTest.class);
+        suite.addTestSuite(ClassTest.class);
+        //To be unccommented when Bug #799327 is fixed.
+        //suite.addTestSuite(ClassLoaderTest.class);
+        suite.addTestSuite(LineNumberReaderTest.class);
+        suite.addTestSuite(InputStreamReaderTest.class);
+        suite.addTestSuite(OutputStreamWriterTest.class);
+        suite.addTestSuite(EnumTest.class);
+        suite.addTestSuite(ParseIntTest.class);
+        suite.addTestSuite(PipedStreamTest.class);
+        suite.addTestSuite(LocaleTest.class);
+        //Commenting out until we find a better way to exclude from continuous testing.
+        //suite.addTestSuite(InetAddrTest.class);
+        suite.addTestSuite(SocketTest.class);
+        suite.addTestSuite(ChecksumTest.class);
+        suite.addTestSuite(DeflateTest.class);
+        suite.addTestSuite(ZipStreamTest.class);
+        suite.addTestSuite(GZIPStreamTest.class);
+        suite.addTestSuite(ZipFileTest.class);
+        suite.addTestSuite(FileTest.class);
+        suite.addTestSuite(SQLiteJDBCDriverTest.class);
+        suite.addTestSuite(AtParserTest.class);
+        suite.addTestSuite(DatagramTest.class);
+        suite.addTestSuite(CryptoTest.class);
+        suite.addTestSuite(MiscRegressionTest.class);
+
+        return suite;
+    }
+}
diff --git a/tests/CoreTests/android/core/LineNumberReaderTest.java b/tests/CoreTests/android/core/LineNumberReaderTest.java
new file mode 100644
index 0000000..6380ebe
--- /dev/null
+++ b/tests/CoreTests/android/core/LineNumberReaderTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Checks basic functionality for LineNumberReader.
+ */
+public class LineNumberReaderTest extends TestCase {
+
+    @MediumTest
+    public void testLineNumberReader() throws Exception {
+        String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz";
+
+        StringReader aa = new StringReader(str);
+        StringReader ba = new StringReader(str);
+        StringReader ca = new StringReader(str);
+        StringReader da = new StringReader(str);
+        StringReader ea = new StringReader(str);
+
+        LineNumberReader a = new LineNumberReader(aa);
+        try {
+            assertEquals(0, a.getLineNumber());
+            assertEquals(str, IOUtil.read(a));
+            assertEquals(1, a.getLineNumber());
+            a.setLineNumber(5);
+            assertEquals(5, a.getLineNumber());
+        } finally {
+            a.close();
+        }
+
+        LineNumberReader b = new LineNumberReader(ba);
+        try {
+            assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+        } finally {
+            b.close();
+        }
+
+        LineNumberReader c = new LineNumberReader(ca);
+        try {
+            assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c));
+        } finally {
+            c.close();
+        }
+
+        LineNumberReader d = new LineNumberReader(da);
+        try {
+            assertEquals("AbCdEfGdEfGhIjKlM\nOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+        } finally {
+            d.close();
+        }
+
+        LineNumberReader e = new LineNumberReader(ea);
+        try {
+            assertEquals("AbCdEfGhIjKlM", e.readLine());
+        } finally {
+            e.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/LocaleTest.java b/tests/CoreTests/android/core/LocaleTest.java
new file mode 100644
index 0000000..700cf1d
--- /dev/null
+++ b/tests/CoreTests/android/core/LocaleTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.nio.charset.Charset;
+import java.text.DateFormatSymbols;
+import java.util.Calendar;
+import java.util.Currency;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TimeZone;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Test some locale-dependent stuff for Android. This test mainly ensures that
+ * our ICU configuration is correct and contains all the needed locales and
+ * resource bundles. 
+ */
+public class LocaleTest extends TestCase {
+
+    // Test basic Locale infrastructure.
+    @SmallTest
+    public void testLocale() throws Exception {
+        Locale locale = new Locale("en");
+        assertEquals("en", locale.toString());
+
+        locale = new Locale("en", "US");
+        assertEquals("en_US", locale.toString());
+
+        locale = new Locale("en", "", "POSIX");
+        assertEquals("en__POSIX", locale.toString());
+
+        locale = new Locale("en", "US", "POSIX");
+        assertEquals("en_US_POSIX", locale.toString());
+    }
+
+    // Test some must-have locales.
+    @LargeTest
+    public void testResourceBundles() throws Exception {
+        Locale eng = new Locale("en", "US");
+        DateFormatSymbols engSymbols = new DateFormatSymbols(eng);
+        
+        Locale deu = new Locale("de", "DE");
+        DateFormatSymbols deuSymbols = new DateFormatSymbols(deu);
+        
+        TimeZone berlin = TimeZone.getTimeZone("Europe/Berlin");
+        
+        assertEquals("January", engSymbols.getMonths()[0]);
+        assertEquals("Januar", deuSymbols.getMonths()[0]);
+
+        assertEquals("Sunday", engSymbols.getWeekdays()[Calendar.SUNDAY]);
+        assertEquals("Sonntag", deuSymbols.getWeekdays()[Calendar.SUNDAY]);
+        
+        assertEquals("Central European Time",
+                berlin.getDisplayName(false, TimeZone.LONG, eng));
+        assertEquals("Central European Summer Time",
+                berlin.getDisplayName(true, TimeZone.LONG, eng));
+
+        assertEquals("Mitteleurop\u00E4ische Zeit",
+                berlin.getDisplayName(false, TimeZone.LONG, deu));
+        assertEquals("Mitteleurop\u00E4ische Sommerzeit",
+                berlin.getDisplayName(true, TimeZone.LONG, deu));
+        
+        assertTrue(engSymbols.getZoneStrings().length > 100);
+    }
+    
+    // Regression test for 1118570: Create test cases for tracking ICU config
+    // changes. This one makes sure we have all necessary locales installed.
+    @MediumTest
+    public void testICULocales() {
+        String[] locales = new String[] {
+                // List of locales currently required for Android.
+                "en_US", "es_US", "en_GB", "fr_FR", "de_DE", "de_AT", "cs_CZ", "nl_NL" };
+        
+        String[] mondays = new String[] {
+                "Monday", "lunes", "Monday", "lundi", "Montag", "Montag", "pond\u011bl\u00ed", "maandag" };
+        
+        String[] currencies = new String[] {
+                "USD", "USD", "GBP", "EUR", "EUR", "EUR", "CZK", "EUR"};
+
+        for (int i = 0; i < locales.length; i++) {
+            Locale l = new Locale(locales[i].substring(0, 2), locales[i].substring(3));
+            
+            // Check language part of locale.
+            DateFormatSymbols d = new DateFormatSymbols(l);
+            assertEquals("Monday name for " + locales[i] + " must match",
+                    mondays[i], d.getWeekdays()[2]);
+            
+            // Check country part of locale.
+            Currency c = Currency.getInstance(l);
+            assertEquals("Currency code for " + locales[i] + " must match",
+                    currencies[i], c.getCurrencyCode());
+        }
+    }
+
+    // Regression test for 1118570: Create test cases for tracking ICU config
+    // changes. This one makes sure we have the necessary converters installed
+    // and don't lose the changes to the converter alias table.
+    @MediumTest
+    public void testICUConverters() {
+        // List of encodings currently required for Android.
+        String[] encodings = new String[] {
+                // Encoding required by the language specification.
+                "US-ASCII",
+                "UTF-8",
+                "UTF-16",
+                "UTF-16BE",
+                "UTF-16LE",
+                "ISO-8859-1",
+                
+                // Additional encodings included in standard ICU
+                "ISO-8859-2",
+                "ISO-8859-3",
+                "ISO-8859-4",
+                "ISO-8859-5",
+                "ISO-8859-6",
+                "ISO-8859-7",
+                "ISO-8859-8",
+                "ISO-8859-8-I",
+                "ISO-8859-9",
+                "ISO-8859-10", 
+                "ISO-8859-11", 
+                "ISO-8859-13",
+                "ISO-8859-14", 
+                "ISO-8859-15",
+                "ISO-8859-16", 
+                "ISO-2022-JP",
+                "Windows-950",
+                "Windows-1250",
+                "Windows-1251",
+                "Windows-1252",
+                "Windows-1253",
+                "Windows-1254",
+                "Windows-1255",
+                "Windows-1256",
+                "Windows-1257",
+                "Windows-1258",              
+                "Big5",
+                "CP864",
+                "CP874",
+                "EUC-CN",
+                "EUC-JP",
+                "KOI8-R",
+                "Macintosh",
+                "GBK",
+                "GB2312",
+                "EUC-KR",
+                
+                // Additional encoding not included in standard ICU.
+                "GSM0338" };
+        
+        for (int i = 0; i < encodings.length; i++) {
+            assertTrue("Charset " + encodings[i] + " must be supported",
+                    Charset.isSupported(encodings[i]));
+            
+            Charset cs = Charset.forName(encodings[i]);
+            android.util.Log.d("LocaleTest", cs.name());
+            
+            Set<String> aliases = cs.aliases();
+            for (String s: aliases) {
+                android.util.Log.d("LocaleTest", " - " + s);
+            }
+        }
+        
+        // Test for valid encoding that is not included in Android. IBM-37 is
+        // a perfect candidate for this, as it is being used for mainframes and
+        // thus somewhat out of the scope of Android.
+        assertFalse("Charset IBM-37 must not be supported",
+                Charset.isSupported("IBM-37"));
+
+        // Test for a bogus encoding.
+        assertFalse("Charset KLINGON must not be supported",
+                Charset.isSupported("KLINGON"));
+        
+        // Make sure our local change to the real translation table used for
+        // EUC-JP doesn't get lost.
+        Charset cs = Charset.forName("EUC-JP");
+        assertTrue("EUC-JP must use 'ibm-954_P101-2007'", cs.aliases().contains("ibm-954_P101-2007"));
+    }
+    
+}
diff --git a/tests/CoreTests/android/core/LowLevelNetRunner.java b/tests/CoreTests/android/core/LowLevelNetRunner.java
new file mode 100644
index 0000000..812ceb5
--- /dev/null
+++ b/tests/CoreTests/android/core/LowLevelNetRunner.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+/**
+ * Provides synchronization handling for low level Request API tests
+ */
+public class LowLevelNetRunner extends Thread {
+
+    private int count = 0;
+
+    LowLevelNetRunner() {
+    }
+
+    public void incrementRunCount() {
+        count++;
+    }
+
+    /**
+     * Decrement the run count. If this returns to zero notify any
+     * test waiting.
+     */
+    public void decrementRunCount() {
+        count--;
+        if (count <= 0) {
+            synchronized (RequestAPITest.syncObj) {
+                RequestAPITest.syncObj.notifyAll();
+            }
+        }
+    }
+
+} /* LowLevelNetRunner*/
diff --git a/tests/CoreTests/android/core/MathTest.java b/tests/CoreTests/android/core/MathTest.java
new file mode 100644
index 0000000..50009db
--- /dev/null
+++ b/tests/CoreTests/android/core/MathTest.java
@@ -0,0 +1,831 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.core;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class MathTest extends TestCase {
+
+    private final double HYP = Math.sqrt(2.0);
+
+    private final double OPP = 1.0;
+
+    private final double ADJ = 1.0;
+
+    /* Required to make previous preprocessor flags work - do not remove */
+    int unused = 0;
+
+    public static void assertEquals(String message, double expected, double actual, double delta) {
+        if (delta == 0D) {
+            Assert.assertEquals(message, expected, actual, Math.ulp(expected));
+        } else {
+            Assert.assertEquals(message, expected, actual, delta);
+        }
+    }
+
+    public static void assertEquals(String message, float expected, float actual, float delta) {
+        if (delta == 0F) {
+            Assert.assertEquals(message, expected, actual, Math.ulp(expected));
+        } else {
+            Assert.assertEquals(message, expected, actual, delta);
+        }
+    }
+    
+    /**
+     * @tests java.lang.Math#abs(double)
+     */
+    @SmallTest
+    public void testAbsD() {
+        // Test for method double java.lang.Math.abs(double)
+
+        assertTrue("Incorrect double abs value",
+                (Math.abs(-1908.8976) == 1908.8976));
+        assertTrue("Incorrect double abs value",
+                (Math.abs(1908.8976) == 1908.8976));
+    }
+
+    /**
+     * @tests java.lang.Math#abs(float)
+     */
+    @SmallTest
+    public void testAbsF() {
+        // Test for method float java.lang.Math.abs(float)
+        assertTrue("Incorrect float abs value",
+                (Math.abs(-1908.8976f) == 1908.8976f));
+        assertTrue("Incorrect float abs value",
+                (Math.abs(1908.8976f) == 1908.8976f));
+    }
+
+    /**
+     * @tests java.lang.Math#abs(int)
+     */
+    @SmallTest
+    public void testAbsI() {
+        // Test for method int java.lang.Math.abs(int)
+        assertTrue("Incorrect int abs value", (Math.abs(-1908897) == 1908897));
+        assertTrue("Incorrect int abs value", (Math.abs(1908897) == 1908897));
+    }
+
+    /**
+     * @tests java.lang.Math#abs(long)
+     */
+    @SmallTest
+    public void testAbsJ() {
+        // Test for method long java.lang.Math.abs(long)
+        assertTrue("Incorrect long abs value",
+                (Math.abs(-19088976000089L) == 19088976000089L));
+        assertTrue("Incorrect long abs value",
+                (Math.abs(19088976000089L) == 19088976000089L));
+    }
+
+    /**
+     * @tests java.lang.Math#acos(double)
+     */
+    @SmallTest
+    public void testAcosD() {
+        // Test for method double java.lang.Math.acos(double)
+        double r = Math.cos(Math.acos(ADJ / HYP));
+        long lr = Double.doubleToLongBits(r);
+        long t = Double.doubleToLongBits(ADJ / HYP);
+        assertTrue("Returned incorrect arc cosine", lr == t || (lr + 1) == t
+                || (lr - 1) == t);
+    }
+
+    /**
+     * @tests java.lang.Math#asin(double)
+     */
+    @SmallTest
+    public void testAsinD() {
+        // Test for method double java.lang.Math.asin(double)
+        double r = Math.sin(Math.asin(OPP / HYP));
+        long lr = Double.doubleToLongBits(r);
+        long t = Double.doubleToLongBits(OPP / HYP);
+        assertTrue("Returned incorrect arc sine", lr == t || (lr + 1) == t
+                || (lr - 1) == t);
+    }
+
+    /**
+     * @tests java.lang.Math#atan(double)
+     */
+    @SmallTest
+    public void testAtanD() {
+        // Test for method double java.lang.Math.atan(double)
+        double answer = Math.tan(Math.atan(1.0));
+        assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+                && answer >= 9.9999999999999983E-1);
+    }
+
+    /**
+     * @tests java.lang.Math#atan2(double, double)
+     */
+    @SmallTest
+    public void testAtan2DD() {
+        // Test for method double java.lang.Math.atan2(double, double)
+        double answer = Math.atan(Math.tan(1.0));
+        assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+                && answer >= 9.9999999999999983E-1);
+    }
+    
+     /**
+     * @tests java.lang.Math#cbrt(double)
+     */
+    @SmallTest
+    public void testCbrtD() {
+        //Test for special situations
+        assertTrue("Should return Double.NaN", Double.isNaN(Math
+                .cbrt(Double.NaN)));
+        assertEquals("Should return Double.POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math
+                        .cbrt(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Should return Double.NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, Math
+                        .cbrt(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+                .cbrt(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double.doubleToLongBits(Math
+                .cbrt(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double.doubleToLongBits(Math
+                .cbrt(-0.0)));
+
+        assertEquals("Should return 3.0", 3.0, Math.cbrt(27.0), 0D);
+        assertEquals("Should return 23.111993172558684", 23.111993172558684,
+                Math.cbrt(12345.6), 0D);
+        assertEquals("Should return 5.643803094122362E102",
+                5.643803094122362E102, Math.cbrt(Double.MAX_VALUE), 0D);
+        assertEquals("Should return 0.01", 0.01, Math.cbrt(0.000001), 0D);
+
+        assertEquals("Should return -3.0", -3.0, Math.cbrt(-27.0), 0D);
+        assertEquals("Should return -23.111993172558684", -23.111993172558684,
+                Math.cbrt(-12345.6), 0D);
+        assertEquals("Should return 1.7031839360032603E-108",
+                1.7031839360032603E-108, Math.cbrt(Double.MIN_VALUE), 0D);
+        assertEquals("Should return -0.01", -0.01, Math.cbrt(-0.000001), 0D);
+    }
+
+    /**
+     * @tests java.lang.Math#ceil(double)
+     */
+    @SmallTest
+    public void testCeilD() {
+        // Test for method double java.lang.Math.ceil(double)
+                assertEquals("Incorrect ceiling for double",
+                             79, Math.ceil(78.89), 0);
+        assertEquals("Incorrect ceiling for double",
+                             -78, Math.ceil(-78.89), 0);
+    }
+
+    /**
+     * @tests java.lang.Math#cos(double)
+     */
+    @SmallTest
+    public void testCosD() {
+        // Test for method double java.lang.Math.cos(double)
+        assertEquals("Incorrect answer", 1.0, Math.cos(0), 0D);
+        assertEquals("Incorrect answer", 0.5403023058681398, Math.cos(1), 0D);
+    }
+
+    /**
+     * @tests java.lang.Math#cosh(double)
+     */
+    @SmallTest
+    public void testCoshD() {
+        // Test for special situations
+        assertTrue(Double.isNaN(Math.cosh(Double.NaN)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.cosh(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.cosh(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals("Should return 1.0", 1.0, Math.cosh(+0.0), 0D);
+        assertEquals("Should return 1.0", 1.0, Math.cosh(-0.0), 0D);
+
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.cosh(1234.56), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.cosh(-1234.56), 0D);
+        assertEquals("Should return 1.0000000000005", 1.0000000000005, Math
+                .cosh(0.000001), 0D);
+        assertEquals("Should return 1.0000000000005", 1.0000000000005, Math
+                .cosh(-0.000001), 0D);
+        assertEquals("Should return 5.212214351945598", 5.212214351945598, Math
+                .cosh(2.33482), 0D);
+
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.cosh(Double.MAX_VALUE), 0D);
+        assertEquals("Should return 1.0", 1.0, Math.cosh(Double.MIN_VALUE), 0D);
+    }
+    
+    /**
+     * @tests java.lang.Math#exp(double)
+     */
+    @SmallTest
+    public void testExpD() {
+        // Test for method double java.lang.Math.exp(double)
+        assertTrue("Incorrect answer returned for simple power", Math.abs(Math
+                .exp(4D)
+                - Math.E * Math.E * Math.E * Math.E) < 0.1D);
+        assertTrue("Incorrect answer returned for larger power", Math.log(Math
+                .abs(Math.exp(5.5D)) - 5.5D) < 10.0D);
+    }
+    
+    /**
+     * @tests java.lang.Math#expm1(double)
+     */
+    @SmallTest
+    public void testExpm1D() {
+        // Test for special cases
+        assertTrue("Should return NaN", Double.isNaN(Math.expm1(Double.NaN)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.expm1(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Should return -1.0", -1.0, Math
+                .expm1(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+                .expm1(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(Math.expm1(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(Math.expm1(-0.0)));
+
+        assertEquals("Should return -9.999950000166666E-6",
+                -9.999950000166666E-6, Math.expm1(-0.00001), 0D);
+        assertEquals("Should return 1.0145103074469635E60",
+                1.0145103074469635E60, Math.expm1(138.16951162), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math
+                        .expm1(123456789123456789123456789.4521584223), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.expm1(Double.MAX_VALUE), 0D);
+        assertEquals("Should return MIN_VALUE", Double.MIN_VALUE, Math
+                .expm1(Double.MIN_VALUE), 0D);
+    }
+
+    /**
+     * @tests java.lang.Math#floor(double)
+     */
+    @SmallTest
+    public void testFloorD() {
+        // Test for method double java.lang.Math.floor(double)
+                assertEquals("Incorrect floor for double",
+                             78, Math.floor(78.89), 0);
+        assertEquals("Incorrect floor for double",
+                             -79, Math.floor(-78.89), 0);
+    }
+    
+    /**
+     * @tests java.lang.Math#hypot(double, double)
+     */
+    @SmallTest
+    public void testHypotDD() {
+        // Test for special cases
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.hypot(Double.POSITIVE_INFINITY,
+                        1.0), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.hypot(Double.NEGATIVE_INFINITY,
+                        123.324), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.hypot(-758.2587,
+                        Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.hypot(5687.21,
+                        Double.NEGATIVE_INFINITY), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.hypot(Double.POSITIVE_INFINITY,
+                        Double.NEGATIVE_INFINITY), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.hypot(Double.NEGATIVE_INFINITY,
+                        Double.POSITIVE_INFINITY), 0D);        
+        assertTrue("Should be NaN", Double.isNaN(Math.hypot(Double.NaN,
+                2342301.89843)));
+        assertTrue("Should be NaN", Double.isNaN(Math.hypot(-345.2680,
+                Double.NaN)));        
+
+        assertEquals("Should return 2396424.905416697", 2396424.905416697, Math
+                .hypot(12322.12, -2396393.2258), 0D);
+        assertEquals("Should return 138.16958070558556", 138.16958070558556,
+                Math.hypot(-138.16951162, 0.13817035864), 0D);
+        assertEquals("Should return 1.7976931348623157E308",
+                1.7976931348623157E308, Math.hypot(Double.MAX_VALUE, 211370.35), 0D);
+        assertEquals("Should return 5413.7185", 5413.7185, Math.hypot(
+                -5413.7185, Double.MIN_VALUE), 0D);
+    }
+
+    /**
+     * @tests java.lang.Math#IEEEremainder(double, double)
+     */
+    @SmallTest
+    public void testIEEEremainderDD() {
+        // Test for method double java.lang.Math.IEEEremainder(double, double)
+        assertEquals("Incorrect remainder returned",
+                0.0, Math.IEEEremainder(1.0, 1.0), 0D);
+        assertTrue("Incorrect remainder returned", Math.IEEEremainder(1.32,
+                89.765) >= 1.4705063220631647E-2
+                || Math.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2);
+    }
+
+    /**
+     * @tests java.lang.Math#log(double)
+     */
+    @SmallTest
+    public void testLogD() {
+        // Test for method double java.lang.Math.log(double)
+        for (double d = 10; d >= -10; d -= 0.5) {
+            double answer = Math.log(Math.exp(d));
+            assertTrue("Answer does not equal expected answer for d = " + d
+                    + " answer = " + answer, Math.abs(answer - d) <= Math
+                    .abs(d * 0.00000001));
+        }
+    }
+    
+    /**
+     * @tests java.lang.Math#log10(double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testLog10D() {
+        // Test for special cases
+        assertTrue(Double.isNaN(Math.log10(Double.NaN)));
+        assertTrue(Double.isNaN(Math.log10(-2541.05745687234187532)));
+        assertTrue(Double.isNaN(Math.log10(-0.1)));
+        assertEquals(Double.POSITIVE_INFINITY, Math.log10(Double.POSITIVE_INFINITY));
+        assertEquals(Double.NEGATIVE_INFINITY, Math.log10(0.0));
+        assertEquals(Double.NEGATIVE_INFINITY, Math.log10(+0.0));
+        assertEquals(Double.NEGATIVE_INFINITY, Math.log10(-0.0));
+        
+        assertEquals(3.0, Math.log10(1000.0));
+        assertEquals(14.0, Math.log10(Math.pow(10, 14)));
+        assertEquals(3.7389561269540406, Math.log10(5482.2158));
+        assertEquals(14.661551142893833, Math.log10(458723662312872.125782332587));
+        assertEquals(-0.9083828622192334, Math.log10(0.12348583358871));
+        assertEquals(308.25471555991675, Math.log10(Double.MAX_VALUE));
+        assertEquals(-323.3062153431158, Math.log10(Double.MIN_VALUE));
+    }
+    
+    /**
+     * @tests java.lang.Math#log1p(double)
+     */
+    @SmallTest
+    public void testLog1pD() {
+        // Test for special cases
+        assertTrue("Should return NaN", Double.isNaN(Math.log1p(Double.NaN)));
+        assertTrue("Should return NaN", Double.isNaN(Math.log1p(-32.0482175)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.log1p(Double.POSITIVE_INFINITY), 0D);
+        assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+                .log1p(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(Math.log1p(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(Math.log1p(-0.0)));
+
+        assertEquals("Should return -0.2941782295312541", -0.2941782295312541,
+                Math.log1p(-0.254856327), 0D);
+        assertEquals("Should return 7.368050685564151", 7.368050685564151, Math
+                .log1p(1583.542), 0D);
+        assertEquals("Should return 0.4633708685409921", 0.4633708685409921,
+                Math.log1p(0.5894227), 0D);
+        assertEquals("Should return 709.782712893384", 709.782712893384, Math
+                .log1p(Double.MAX_VALUE), 0D);
+        assertEquals("Should return Double.MIN_VALUE", Double.MIN_VALUE, Math
+                .log1p(Double.MIN_VALUE), 0D);
+    }
+
+    /**
+     * @tests java.lang.Math#max(double, double)
+     */
+    @SmallTest
+    public void testMaxDD() {
+        // Test for method double java.lang.Math.max(double, double)
+        assertEquals("Incorrect double max value", 1908897.6000089, Math.max(-1908897.6000089,
+                1908897.6000089), 0D);
+        assertEquals("Incorrect double max value",
+                1908897.6000089, Math.max(2.0, 1908897.6000089), 0D);
+        assertEquals("Incorrect double max value", -2.0, Math.max(-2.0,
+                -1908897.6000089), 0D);
+
+    }
+
+    /**
+     * @tests java.lang.Math#max(float, float)
+     */
+    @SmallTest
+    public void testMaxFF() {
+        // Test for method float java.lang.Math.max(float, float)
+        assertTrue("Incorrect float max value", Math.max(-1908897.600f,
+                1908897.600f) == 1908897.600f);
+        assertTrue("Incorrect float max value",
+                Math.max(2.0f, 1908897.600f) == 1908897.600f);
+        assertTrue("Incorrect float max value",
+                Math.max(-2.0f, -1908897.600f) == -2.0f);
+    }
+
+    /**
+     * @tests java.lang.Math#max(int, int)
+     */
+    @SmallTest
+    public void testMaxII() {
+        // Test for method int java.lang.Math.max(int, int)
+        assertEquals("Incorrect int max value",
+                19088976, Math.max(-19088976, 19088976));
+        assertEquals("Incorrect int max value",
+                19088976, Math.max(20, 19088976));
+        assertEquals("Incorrect int max value", -20, Math.max(-20, -19088976));
+    }
+
+    /**
+     * @tests java.lang.Math#max(long, long)
+     */
+    @SmallTest
+    public void testMaxJJ() {
+        // Test for method long java.lang.Math.max(long, long)
+        assertEquals("Incorrect long max value", 19088976000089L, Math.max(-19088976000089L,
+                19088976000089L));
+        assertEquals("Incorrect long max value",
+                19088976000089L, Math.max(20, 19088976000089L));
+        assertEquals("Incorrect long max value",
+                -20, Math.max(-20, -19088976000089L));
+    }
+
+    /**
+     * @tests java.lang.Math#min(double, double)
+     */
+    @SmallTest
+    public void testMinDD() {
+        // Test for method double java.lang.Math.min(double, double)
+        assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-1908897.6000089,
+                1908897.6000089), 0D);
+        assertEquals("Incorrect double min value",
+                2.0, Math.min(2.0, 1908897.6000089), 0D);
+        assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-2.0,
+                -1908897.6000089), 0D);
+    }
+
+    /**
+     * @tests java.lang.Math#min(float, float)
+     */
+    @SmallTest
+    public void testMinFF() {
+        // Test for method float java.lang.Math.min(float, float)
+        assertTrue("Incorrect float min value", Math.min(-1908897.600f,
+                1908897.600f) == -1908897.600f);
+        assertTrue("Incorrect float min value",
+                Math.min(2.0f, 1908897.600f) == 2.0f);
+        assertTrue("Incorrect float min value",
+                Math.min(-2.0f, -1908897.600f) == -1908897.600f);
+    }
+
+    /**
+     * @tests java.lang.Math#min(int, int)
+     */
+    @SmallTest
+    public void testMinII() {
+        // Test for method int java.lang.Math.min(int, int)
+        assertEquals("Incorrect int min value",
+                -19088976, Math.min(-19088976, 19088976));
+        assertEquals("Incorrect int min value", 20, Math.min(20, 19088976));
+        assertEquals("Incorrect int min value",
+                -19088976, Math.min(-20, -19088976));
+
+    }
+
+    /**
+     * @tests java.lang.Math#min(long, long)
+     */
+    @SmallTest
+    public void testMinJJ() {
+        // Test for method long java.lang.Math.min(long, long)
+        assertEquals("Incorrect long min value", -19088976000089L, Math.min(-19088976000089L,
+                19088976000089L));
+        assertEquals("Incorrect long min value",
+                20, Math.min(20, 19088976000089L));
+        assertEquals("Incorrect long min value",
+                -19088976000089L, Math.min(-20, -19088976000089L));
+    }
+
+    /**
+     * @tests java.lang.Math#pow(double, double)
+     */
+    @SmallTest
+    public void testPowDD() {
+        // Test for method double java.lang.Math.pow(double, double)
+        assertTrue("pow returned incorrect value",
+                (long) Math.pow(2, 8) == 256l);
+        assertTrue("pow returned incorrect value",
+                Math.pow(2, -8) == 0.00390625d);
+        assertEquals("Incorrect root returned1",
+                             2, Math.sqrt(Math.pow(Math.sqrt(2), 4)), 0);
+    }
+
+    /**
+     * @tests java.lang.Math#rint(double)
+     */
+    @SmallTest
+    public void testRintD() {
+        // Test for method double java.lang.Math.rint(double)
+        assertEquals("Failed to round properly - up to odd",
+                3.0, Math.rint(2.9), 0D);
+        assertTrue("Failed to round properly - NaN", Double.isNaN(Math
+                .rint(Double.NaN)));
+        assertEquals("Failed to round properly down  to even",
+                2.0, Math.rint(2.1), 0D);
+        assertTrue("Failed to round properly " + 2.5 + " to even", Math
+                .rint(2.5) == 2.0);
+    }
+
+    /**
+     * @tests java.lang.Math#round(double)
+     */
+    @SmallTest
+    public void testRoundD() {
+        // Test for method long java.lang.Math.round(double)
+        assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89d));
+    }
+
+    /**
+     * @tests java.lang.Math#round(float)
+     */
+    @SmallTest
+    public void testRoundF() {
+        // Test for method int java.lang.Math.round(float)
+        assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89f));
+    }
+    
+    /**
+     * @tests java.lang.Math#signum(double)
+     */
+    @SmallTest
+    public void testSignumD() {
+        assertTrue(Double.isNaN(Math.signum(Double.NaN)));
+        assertTrue(Double.isNaN(Math.signum(Double.NaN)));
+        assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+                .signum(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(Math.signum(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(Math.signum(-0.0)));
+
+        assertEquals(1.0, Math.signum(253681.2187962), 0D);
+        assertEquals(-1.0, Math.signum(-125874693.56), 0D);
+        assertEquals(1.0, Math.signum(1.2587E-308), 0D);
+        assertEquals(-1.0, Math.signum(-1.2587E-308), 0D);
+
+        assertEquals(1.0, Math.signum(Double.MAX_VALUE), 0D);
+        assertEquals(1.0, Math.signum(Double.MIN_VALUE), 0D);
+        assertEquals(-1.0, Math.signum(-Double.MAX_VALUE), 0D);
+        assertEquals(-1.0, Math.signum(-Double.MIN_VALUE), 0D);
+        assertEquals(1.0, Math.signum(Double.POSITIVE_INFINITY), 0D);
+        assertEquals(-1.0, Math.signum(Double.NEGATIVE_INFINITY), 0D);
+    }
+
+    /**
+     * @tests java.lang.Math#signum(float)
+     */
+    @SmallTest
+    public void testSignumF() {
+        assertTrue(Float.isNaN(Math.signum(Float.NaN)));
+        assertEquals(Float.floatToIntBits(0.0f), Float
+                .floatToIntBits(Math.signum(0.0f)));
+        assertEquals(Float.floatToIntBits(+0.0f), Float
+                .floatToIntBits(Math.signum(+0.0f)));
+        assertEquals(Float.floatToIntBits(-0.0f), Float
+                .floatToIntBits(Math.signum(-0.0f)));
+
+        assertEquals(1.0f, Math.signum(253681.2187962f), 0f);
+        assertEquals(-1.0f, Math.signum(-125874693.56f), 0f);
+        assertEquals(1.0f, Math.signum(1.2587E-11f), 0f);
+        assertEquals(-1.0f, Math.signum(-1.2587E-11f), 0f);
+
+        assertEquals(1.0f, Math.signum(Float.MAX_VALUE), 0f);
+        assertEquals(1.0f, Math.signum(Float.MIN_VALUE), 0f);
+        assertEquals(-1.0f, Math.signum(-Float.MAX_VALUE), 0f);
+        assertEquals(-1.0f, Math.signum(-Float.MIN_VALUE), 0f);
+        assertEquals(1.0f, Math.signum(Float.POSITIVE_INFINITY), 0f);
+        assertEquals(-1.0f, Math.signum(Float.NEGATIVE_INFINITY), 0f);
+    }
+
+    /**
+     * @tests java.lang.Math#sin(double)
+     */
+    @SmallTest
+    public void testSinD() {
+        // Test for method double java.lang.Math.sin(double)
+        assertEquals("Incorrect answer", 0.0, Math.sin(0), 0D);
+        assertEquals("Incorrect answer", 0.8414709848078965, Math.sin(1), 0D);
+    }
+    
+    /**
+     * @tests java.lang.Math#sinh(double)
+     */
+    @SmallTest
+    public void testSinhD() {
+        // Test for special situations
+        assertTrue("Should return NaN", Double.isNaN(Math.sinh(Double.NaN)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.sinh(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Should return NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, Math.sinh(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+                .sinh(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(Math.sinh(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(Math.sinh(-0.0)));
+
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.sinh(1234.56), 0D);
+        assertEquals("Should return NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, Math.sinh(-1234.56), 0D);
+        assertEquals("Should return 1.0000000000001666E-6",
+                1.0000000000001666E-6, Math.sinh(0.000001), 0D);
+        assertEquals("Should return -1.0000000000001666E-6",
+                -1.0000000000001666E-6, Math.sinh(-0.000001), 0D);
+        assertEquals("Should return 5.115386441963859", 5.115386441963859, Math
+                .sinh(2.33482), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, Math.sinh(Double.MAX_VALUE), 0D);
+        assertEquals("Should return 4.9E-324", 4.9E-324, Math
+                .sinh(Double.MIN_VALUE), 0D);
+    }
+    
+    /**
+     * @tests java.lang.Math#sqrt(double)
+     */
+    @SmallTest
+    public void testSqrtD() {
+        // Test for method double java.lang.Math.sqrt(double)
+                assertEquals("Incorrect root returned2", 7, Math.sqrt(49), 0);
+    }
+
+    /**
+     * @tests java.lang.Math#tan(double)
+     */
+    @SmallTest
+    public void testTanD() {
+        // Test for method double java.lang.Math.tan(double)
+        assertEquals("Incorrect answer", 0.0, Math.tan(0), 0D);
+        assertEquals("Incorrect answer", 1.5574077246549023, Math.tan(1), 0D);
+
+    }
+
+    /**
+     * @tests java.lang.Math#tanh(double)
+     */
+    @SmallTest
+    public void testTanhD() {
+        // Test for special situations
+        assertTrue("Should return NaN", Double.isNaN(Math.tanh(Double.NaN)));
+        assertEquals("Should return +1.0", +1.0, Math
+                .tanh(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Should return -1.0", -1.0, Math
+                .tanh(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+                .tanh(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(Math.tanh(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(Math.tanh(-0.0)));
+
+        assertEquals("Should return 1.0", 1.0, Math.tanh(1234.56), 0D);
+        assertEquals("Should return -1.0", -1.0, Math.tanh(-1234.56), 0D);
+        assertEquals("Should return 9.999999999996666E-7",
+                9.999999999996666E-7, Math.tanh(0.000001), 0D);
+        assertEquals("Should return 0.981422884124941", 0.981422884124941, Math
+                .tanh(2.33482), 0D);
+        assertEquals("Should return 1.0", 1.0, Math.tanh(Double.MAX_VALUE), 0D);
+        assertEquals("Should return 4.9E-324", 4.9E-324, Math
+                .tanh(Double.MIN_VALUE), 0D);
+    }
+    
+    /**
+     * @tests java.lang.Math#random()
+     */
+    @MediumTest
+    public void testRandom() {
+        // There isn't a place for these tests so just stick them here
+        assertEquals("Wrong value E",
+                4613303445314885481L, Double.doubleToLongBits(Math.E));
+        assertEquals("Wrong value PI",
+                4614256656552045848L, Double.doubleToLongBits(Math.PI));
+
+        for (int i = 500; i >= 0; i--) {
+            double d = Math.random();
+            assertTrue("Generated number is out of range: " + d, d >= 0.0
+                    && d < 1.0);
+        }
+    }
+
+    /**
+     * @tests java.lang.Math#toRadians(double)
+     */
+    @MediumTest
+    public void testToRadiansD() {
+        for (double d = 500; d >= 0; d -= 1.0) {
+            double converted = Math.toDegrees(Math.toRadians(d));
+            assertTrue("Converted number not equal to original. d = " + d,
+                    converted >= d * 0.99999999 && converted <= d * 1.00000001);
+        }
+    }
+
+    /**
+     * @tests java.lang.Math#toDegrees(double)
+     */
+    @MediumTest
+    public void testToDegreesD() {
+        for (double d = 500; d >= 0; d -= 1.0) {
+            double converted = Math.toRadians(Math.toDegrees(d));
+            assertTrue("Converted number not equal to original. d = " + d,
+                    converted >= d * 0.99999999 && converted <= d * 1.00000001);
+        }
+    }
+    
+    /**
+     * @tests java.lang.Math#ulp(double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testUlpD() {
+        // Test for special cases
+        assertTrue("Should return NaN", Double.isNaN(Math.ulp(Double.NaN)));
+        assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math
+                .ulp(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math
+                .ulp(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+                .ulp(0.0), 0D);
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+                .ulp(+0.0), 0D);
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+                .ulp(-0.0), 0D);
+        assertEquals("Returned incorrect value", Math.pow(2, 971), Math
+                .ulp(Double.MAX_VALUE), 0D);
+        assertEquals("Returned incorrect value", Math.pow(2, 971), Math
+                .ulp(-Double.MAX_VALUE), 0D);
+
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+                .ulp(Double.MIN_VALUE), 0D);
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+                .ulp(-Double.MIN_VALUE), 0D);
+
+        assertEquals("Returned incorrect value", 2.220446049250313E-16, Math
+                .ulp(1.0), 0D);
+        assertEquals("Returned incorrect value", 2.220446049250313E-16, Math
+                .ulp(-1.0), 0D);
+        assertEquals("Returned incorrect value", 2.2737367544323206E-13, Math
+                .ulp(1153.0), 0D);
+    }
+
+    /**
+     * @tests java.lang.Math#ulp(float)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testUlpf() {
+        // Test for special cases
+        assertTrue("Should return NaN", Float.isNaN(Math.ulp(Float.NaN)));
+        assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math
+                .ulp(Float.POSITIVE_INFINITY), 0f);
+        assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math
+                .ulp(Float.NEGATIVE_INFINITY), 0f);
+        assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+                .ulp(0.0f), 0f);
+        assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+                .ulp(+0.0f), 0f);
+        assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+                .ulp(-0.0f), 0f);
+        assertEquals("Returned incorrect value", 2.028241E31f, Math
+                .ulp(Float.MAX_VALUE), 0f);
+        assertEquals("Returned incorrect value", 2.028241E31f, Math
+                .ulp(-Float.MAX_VALUE), 0f);
+
+        assertEquals("Returned incorrect value", 1.4E-45f, Math
+                .ulp(Float.MIN_VALUE), 0f);
+        assertEquals("Returned incorrect value", 1.4E-45f, Math
+                .ulp(-Float.MIN_VALUE), 0f);
+
+        assertEquals("Returned incorrect value", 1.1920929E-7f, Math.ulp(1.0f),
+                0f);
+        assertEquals("Returned incorrect value", 1.1920929E-7f,
+                Math.ulp(-1.0f), 0f);
+        assertEquals("Returned incorrect value", 1.2207031E-4f, Math
+                .ulp(1153.0f), 0f);
+        assertEquals("Returned incorrect value", 5.6E-45f, Math
+                .ulp(9.403954E-38f), 0f);
+    }
+}
diff --git a/tests/CoreTests/android/core/MiscRegressionTest.java b/tests/CoreTests/android/core/MiscRegressionTest.java
new file mode 100644
index 0000000..8fe064c
--- /dev/null
+++ b/tests/CoreTests/android/core/MiscRegressionTest.java
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+import java.util.ConcurrentModificationException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Random;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.logging.Logger;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class MiscRegressionTest extends TestCase {
+
+    // Regression test for #857840: want JKS key store
+    @SmallTest
+    public void testDefaultKeystore() {
+        String type = KeyStore.getDefaultType();
+        Assert.assertEquals("Default keystore type must be Bouncy Castle", "BKS", type);
+
+        try {
+            KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
+            Assert.assertNotNull("Keystore must not be null", store);
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+        
+        try {
+            KeyStore store = KeyStore.getInstance("BKS");
+            Assert.assertNotNull("Keystore must not be null", store);
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    // Regression test for #1061945: negative Shorts do not
+    // serialize/deserialize correctly
+    @SmallTest
+    public void testShortSerialization() throws Exception {
+        // create an instance of ObjectInputStream
+        String x = new String("serialize_foobar");
+        java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
+        (new java.io.ObjectOutputStream(baos)).writeObject(x);
+        ObjectInputStream ois = new java.io.ObjectInputStream(
+                new java.io.ByteArrayInputStream(baos.toByteArray()));
+
+        // get the setField(...,, short val) method in question
+        Class<ObjectInputStream> oClass = ObjectInputStream.class;
+        Method m = oClass.getDeclaredMethod("setField", new Class[] { Object.class, Class.class, String.class, short.class});
+        // compose args
+        short start = 123;
+        short origval = -1; // 0xffff
+        Short obj = new Short(start);
+        Class<Short> declaringClass = Short.class;
+        String fieldDescName = "value";
+
+        // test the initial value
+        assertEquals(obj.shortValue(), start);
+        // invoke native method to set the field "value" of type short to the newval
+        m.setAccessible(true); // since the method is private
+        m.invoke(ois, new Object[]{ obj, declaringClass, fieldDescName, new Short(origval)} );
+        // test the set value
+        short res = obj.shortValue();
+        assertEquals("Read and written values must be equal", origval, res);
+    }
+    
+    // Regression test for #951285: Suitable LogHandler should be chosen
+    // depending on the environment.
+    @MediumTest
+    public void testAndroidLogHandler() throws Exception {
+        Logger.global.severe("This has logging Level.SEVERE, should become ERROR");
+        Logger.global.warning("This has logging Level.WARNING, should become WARN");
+        Logger.global.info("This has logging Level.INFO, should become INFO");
+        Logger.global.config("This has logging Level.CONFIG, should become DEBUG");
+        Logger.global.fine("This has logging Level.FINE, should become VERBOSE");
+        Logger.global.finer("This has logging Level.FINER, should become VERBOSE");
+        Logger.global.finest("This has logging Level.FINEST, should become VERBOSE");
+    }
+
+    // Regression test for #1045939: Different output for Method.toString()
+    @SmallTest
+    public void testMethodToString() {
+        try {
+            Method m1 = Object.class.getMethod("notify", new Class[] { });
+            Method m2 = Object.class.getMethod("toString", new Class[] { });
+            Method m3 = Object.class.getMethod("wait", new Class[] { long.class, int.class });
+            Method m4 = Object.class.getMethod("equals", new Class[] { Object.class });
+            Method m5 = String.class.getMethod("valueOf", new Class[] { char[].class });
+            Method m6 = Runtime.class.getMethod("exec", new Class[] { String[].class });
+
+            assertEquals("Method.toString() must match expectations",
+                    "public final native void java.lang.Object.notify()",
+                    m1.toString());
+            
+            assertEquals("Method.toString() must match expectations",
+                    "public java.lang.String java.lang.Object.toString()",
+                    m2.toString());
+
+            assertEquals("Method.toString() must match expectations",
+                    "public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException",
+                    m3.toString());
+
+            assertEquals("Method.toString() must match expectations",
+                    "public boolean java.lang.Object.equals(java.lang.Object)",
+                    m4.toString());
+
+            assertEquals("Method.toString() must match expectations",
+                    "public static java.lang.String java.lang.String.valueOf(char[])",
+                    m5.toString());
+
+            assertEquals("Method.toString() must match expectations",
+                    "public java.lang.Process java.lang.Runtime.exec(java.lang.String[]) throws java.io.IOException",
+                    m6.toString());
+
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+
+    }
+
+    // Regression test for #1062200: Enum fails to deserialize. Actual problem
+    // was that Class.isEnum() erroneously returned true for indirect
+    // descendants of Enum.
+    enum TrafficLights {
+        RED,
+        YELLOW {},
+        GREEN {
+            @SuppressWarnings("unused")
+            int i;
+            @SuppressWarnings("unused")
+            void foobar() {}
+        };
+    }
+    
+    @SmallTest
+    public void testClassIsEnum() {
+        Class<?> trafficClass = TrafficLights.class;
+        
+        Class<?> redClass = TrafficLights.RED.getClass();
+        Class<?> yellowClass = TrafficLights.YELLOW.getClass();
+        Class<?> greenClass = TrafficLights.GREEN.getClass();
+        
+        Assert.assertSame("Classes must be equal", trafficClass, redClass);
+        Assert.assertNotSame("Classes must be different", trafficClass, yellowClass);
+        Assert.assertNotSame("Classes must be different", trafficClass, greenClass);
+        Assert.assertNotSame("Classes must be different", yellowClass, greenClass);
+        
+        Assert.assertTrue("Must be an enum", trafficClass.isEnum());
+        Assert.assertTrue("Must be an enum", redClass.isEnum());
+        Assert.assertFalse("Must not be an enum", yellowClass.isEnum());
+        Assert.assertFalse("Must not be an enum", greenClass.isEnum());
+        
+        Assert.assertNotNull("Must have enum constants", trafficClass.getEnumConstants());
+        Assert.assertNull("Must not have enum constants", yellowClass.getEnumConstants());
+        Assert.assertNull("Must not have enum constants", greenClass.getEnumConstants());
+    }
+    
+    // Regression test for #1046174: JarEntry.getCertificates() is really slow.
+    public void checkJarCertificates(File file) {
+        try {
+            JarFile jarFile = new JarFile(file);
+            JarEntry je = jarFile.getJarEntry("AndroidManifest.xml");
+            byte[] readBuffer = new byte[1024];
+            
+            long t0 = System.currentTimeMillis();
+            
+            // We must read the stream for the JarEntry to retrieve
+            // its certificates.
+            InputStream is = jarFile.getInputStream(je);
+            while (is.read(readBuffer, 0, readBuffer.length) != -1) {
+                // not using
+            }
+            is.close();
+            Certificate[] certs = je != null ? je.getCertificates() : null;
+
+            long t1 = System.currentTimeMillis();
+            android.util.Log.d("TestHarness", "loadCertificates() took " + (t1 - t0) + " ms");
+            if (certs == null) {
+                android.util.Log.d("TestHarness", "We have no certificates");
+            } else {
+                android.util.Log.d("TestHarness", "We have " + certs.length + " certificates");
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+    
+    @LargeTest
+    public void testJarCertificates() {
+        File[] files = new File("/system/app").listFiles();
+        for (int i = 0; i < files.length; i++) {
+            checkJarCertificates(files[i]);
+        }
+    }
+    
+    // Regression test for #1120750: Reflection for static long fields is broken
+    private static final long MY_LONG = 5073258162644648461L;
+    
+    @SmallTest
+    public void testLongFieldReflection() {
+        try {
+            Field field = getClass().getDeclaredField("MY_LONG");
+            assertEquals(5073258162644648461L, field.getLong(null));
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    // Regression test for Harmony LinkedHashMap bug. Copied from core, just
+    // to make sure it doesn't get lost.
+    @SmallTest
+    public void testLinkedHashMap() {
+        // we want to test the LinkedHashMap in access ordering mode.
+        LinkedHashMap map = new LinkedHashMap<String, String>(10, 0.75f, true);
+
+        map.put("key1", "value1");
+        map.put("key2", "value2");
+        map.put("key3", "value3");
+
+        Iterator iterator = map.keySet().iterator();
+        String id = (String) iterator.next();
+        map.get(id);
+        try {
+            iterator.next();
+            // A LinkedHashMap is supposed to throw this Exception when a 
+            // iterator.next() Operation takes place after a get
+            // Operation. This is because the get Operation is considered
+            // a structural modification if the LinkedHashMap is in
+            // access order mode.
+            fail("expected ConcurrentModificationException was not thrown.");
+        } catch(ConcurrentModificationException e) {
+            // expected
+        }
+        
+        LinkedHashMap mapClone = (LinkedHashMap) map.clone();
+        
+        iterator = map.keySet().iterator();
+        id = (String) iterator.next();
+        mapClone.get(id);
+        try {
+            iterator.next();
+        } catch(ConcurrentModificationException e) {
+            fail("expected ConcurrentModificationException was not thrown.");
+        }
+    }
+    
+    // Regression test for #1212257: Boot-time package scan is slow. Not
+    // expected to fail. Please see log if you are interested in the results.
+    @LargeTest
+    public void testZipStressManifest() {
+        android.util.Log.d("MiscRegressionTest", "ZIP stress test started");
+        
+        long time0 = System.currentTimeMillis();
+        
+        try {
+            File[] files = new File("/system/app").listFiles();
+
+            byte[] buffer = new byte[512];
+            
+            if (files != null) {
+                for (int i = 0; i < files.length; i++) {
+                    android.util.Log.d("MiscRegressionTest",
+                            "ZIP stress test processing " + files[i] + "...");
+                    
+                    ZipFile zip = new ZipFile(files[i]);
+                    
+                    ZipEntry entry = zip.getEntry("AndroidManifest.xml");
+                    InputStream stream = zip.getInputStream(entry);
+                    
+                    int j = stream.read(buffer);
+                    while (j != -1) {
+                        j = stream.read(buffer);
+                    }
+                    
+                    stream.close();
+                }
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+        
+        long time1 = System.currentTimeMillis();
+        
+        android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " +
+                "time was " + (time1- time0) + "ms");
+    }
+
+    @LargeTest
+    public void testZipStressAllFiles() {
+        android.util.Log.d("MiscRegressionTest", "ZIP stress test started");
+        
+        long time0 = System.currentTimeMillis();
+        
+        try {
+            File[] files = new File("/system/app").listFiles();
+
+            byte[] buffer = new byte[512];
+            
+            if (files != null) {
+                for (int i = 0; i < files.length; i++) {
+                    android.util.Log.d("MiscRegressionTest",
+                            "ZIP stress test processing " + files[i] + "...");
+                    
+                    ZipFile zip = new ZipFile(files[i]);
+                    
+                    Enumeration<? extends ZipEntry> entries = zip.entries();
+                    while (entries.hasMoreElements()) {
+                        InputStream stream = zip.getInputStream(entries.nextElement());
+                        
+                        int j = stream.read(buffer);
+                        while (j != -1) {
+                            j = stream.read(buffer);
+                        }
+                        
+                        stream.close();
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+        
+        long time1 = System.currentTimeMillis();
+        
+        android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " +
+                "time was " + (time1- time0) + "ms");
+    }
+
+    @SmallTest
+    public void testOsEncodingProperty() {
+        long time0 = System.currentTimeMillis();
+        String[] files = new File("/system/app").list();
+        long time1 = System.currentTimeMillis();
+        android.util.Log.d("MiscRegressionTest", "File.list() test finished, " +
+                "time was " + (time1- time0) + "ms");
+    }
+
+    // -------------------------------------------------------------------------
+    // Regression test for #1185084: Native memory allocated by
+    // java.util.zip.Deflater in system_server. The fix reduced some internal
+    // ZLIB buffers in size, so this test is trying to execute a lot of
+    // deflating to ensure that things are still working properly.
+    private void assertEquals(byte[] a, byte[] b) {
+        assertEquals("Arrays must have same length", a.length, b.length);
+        
+        for (int i = 0; i < a.length; i++) {
+            assertEquals("Array elements #" + i + " must be equal", a[i], b[i]);
+        }
+    }
+    
+    @LargeTest
+    public void testZipDeflateInflateStress() {
+        
+        final int DATA_SIZE = 16384;
+
+        Random random = new Random(42); // Seed makes test reproducible
+        
+        try {
+            // Outer loop selects "mode" of test.
+            for (int j = 1; j <=2 ; j++) {
+
+                byte[] input = new byte[DATA_SIZE];
+                
+                if (j == 1) {
+                    // Totally random content
+                    random.nextBytes(input);
+                } else {
+                    // Random contents with longer repetitions
+                    int pos = 0;
+                    while (pos < input.length) {
+                        byte what = (byte)random.nextInt(256);
+                        int howMany = random.nextInt(32);
+                        if (pos + howMany >= input.length) {
+                            howMany = input.length - pos;
+                        }
+                        Arrays.fill(input, pos, pos + howMany, what);
+                        pos += howMany;
+                    }
+                }
+                
+                // Inner loop tries all 9 compression levels.
+                for (int i = 1; i <= 9; i++) {
+                    android.util.Log.d("MiscRegressionTest", "ZipDeflateInflateStress test (" + j + "," + i + ")...");
+                    
+                    byte[] zipped = new byte[2 * DATA_SIZE]; // Just to make sure...
+                    
+                    Deflater deflater = new Deflater(i);
+                    deflater.setInput(input);
+                    deflater.finish();
+                    
+                    deflater.deflate(zipped);
+                    
+                    byte[] output = new byte[DATA_SIZE];
+                    
+                    Inflater inflater = new Inflater();
+                    inflater.setInput(zipped);
+                    inflater.finished();
+    
+                    inflater.inflate(output);
+                    
+                    assertEquals(input, output);
+                }
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+    
+    // -------------------------------------------------------------------------
+    // Regression test for #1252043: Thread.getStackTrace() is broken
+    class MyThread extends Thread {
+        public MyThread(String name) {
+            super(name);
+        }
+        
+        @Override
+        public void run() {
+            doSomething();
+        }
+        
+        public void doSomething() {
+            for (int i = 0; i < 20;) {
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException ex) {
+                }
+            }
+        }
+    }
+
+    class MyOtherThread extends Thread {
+        public int visibleTraces;
+        
+        public MyOtherThread(ThreadGroup group, String name) {
+            super(group, name);
+        }
+        
+        @Override
+        public void run() {
+            visibleTraces = Thread.getAllStackTraces().size();
+        }
+    }
+    
+    @LargeTest
+    public void testThreadGetStackTrace() {
+        MyThread t1 = new MyThread("t1");
+        t1.start();
+        
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException ex) {
+        }
+
+        StackTraceElement[] traces = t1.getStackTrace();
+        StackTraceElement trace = traces[traces.length - 2];
+        
+        // Expect to find MyThread.doSomething in the trace
+        assertTrue("Must find MyThread.doSomething in trace",
+                trace.getClassName().endsWith("$MyThread") && 
+                trace.getMethodName().equals("doSomething"));
+
+        ThreadGroup g1 = new ThreadGroup("1");
+        MyOtherThread t2 = new MyOtherThread(g1, "t2");
+        t2.start();
+        try {
+            t2.join();
+        } catch (InterruptedException ex) {
+        }
+        
+        // Expect to see the traces of all threads (not just t2)
+        assertTrue("Must have traces for all threads", t2.visibleTraces > 1);
+    }
+}
diff --git a/tests/CoreTests/android/core/NIOTest.java b/tests/CoreTests/android/core/NIOTest.java
new file mode 100644
index 0000000..fd279ca
--- /dev/null
+++ b/tests/CoreTests/android/core/NIOTest.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.nio.Buffer;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for some buffers from the java.nio package.
+ */
+public class NIOTest extends TestCase {
+
+    void checkBuffer(Buffer b) {
+        assertTrue(0 <= b.position());
+        assertTrue(b.position() <= b.limit());
+        assertTrue(b.limit() <= b.capacity());
+    }
+
+    @SmallTest
+    public void testNIO() throws Exception {
+        ByteBuffer b;
+
+        // Test byte array-based buffer
+        b = ByteBuffer.allocate(12);
+        byteBufferTest(b);
+
+        // Test native heap-allocated buffer
+        b = ByteBuffer.allocateDirect(12);
+        byteBufferTest(b);
+
+        // Test short array-based buffer
+        short[] shortArray = new short[8];
+        ShortBuffer sb = ShortBuffer.wrap(shortArray);
+        shortBufferTest(sb);
+
+        // Test int array-based buffer
+        int[] intArray = new int[8];
+        IntBuffer ib = IntBuffer.wrap(intArray);
+        intBufferTest(ib);
+
+        // Test float array-based buffer
+        float[] floatArray = new float[8];
+        FloatBuffer fb = FloatBuffer.wrap(floatArray);
+        floatBufferTest(fb);
+    }
+
+    private void byteBufferTest(ByteBuffer b) {
+        checkBuffer(b);
+
+        // Bounds checks
+        try {
+            b.put(-1, (byte) 0);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            b.put(b.limit(), (byte) 0);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // IndexOutOfBoundsException: offset < 0
+        try {
+            byte[] data = new byte[8];
+            b.position(0);
+            b.put(data, -1, 2);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // IndexOutOfBoundsException: length > array.length - offset
+        try {
+            byte[] data = new byte[8];
+            b.position(0);
+            b.put(data, 1, 8);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // BufferOverflowException: length > remaining()
+        try {
+            byte[] data = new byte[8];
+            b.position(b.limit() - 2);
+            b.put(data, 0, 3);
+            fail("expected exception not thrown");
+        } catch (BufferOverflowException e) {
+            // expected
+        }
+
+        // Fill buffer with bytes A0 A1 A2 A3 ...
+        b.position(0);
+        for (int i = 0; i < b.capacity(); i++) {
+            b.put((byte) (0xA0 + i));
+        }
+        try {
+            b.put((byte) 0xFF);
+            fail("expected exception not thrown");
+        } catch (BufferOverflowException e) {
+            // expected
+        }
+
+        b.position(0);
+        assertEquals((byte) 0xA7, b.get(7));
+        try {
+            b.get(12);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            b.get(-10);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        b.position(0);
+        b.order(ByteOrder.LITTLE_ENDIAN);
+        assertEquals((byte) 0xA0, b.get());
+        assertEquals((byte) 0xA1, b.get());
+        assertEquals((byte) 0xA2, b.get());
+        assertEquals((byte) 0xA3, b.get());
+        assertEquals((byte) 0xA4, b.get());
+        assertEquals((byte) 0xA5, b.get());
+        assertEquals((byte) 0xA6, b.get());
+        assertEquals((byte) 0xA7, b.get());
+        assertEquals((byte) 0xA8, b.get());
+        assertEquals((byte) 0xA9, b.get());
+        assertEquals((byte) 0xAA, b.get());
+        assertEquals((byte) 0xAB, b.get());
+        try {
+            b.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        b.position(0);
+        b.order(ByteOrder.BIG_ENDIAN);
+        assertEquals((byte) 0xA0, b.get());
+        assertEquals((byte) 0xA1, b.get());
+        assertEquals((byte) 0xA2, b.get());
+        assertEquals((byte) 0xA3, b.get());
+        assertEquals((byte) 0xA4, b.get());
+        assertEquals((byte) 0xA5, b.get());
+        assertEquals((byte) 0xA6, b.get());
+        assertEquals((byte) 0xA7, b.get());
+        assertEquals((byte) 0xA8, b.get());
+        assertEquals((byte) 0xA9, b.get());
+        assertEquals((byte) 0xAA, b.get());
+        assertEquals((byte) 0xAB, b.get());
+        try {
+            b.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        b.position(6);
+        b.limit(10);
+        assertEquals((byte) 0xA6, b.get());
+
+        // Check sliced buffer
+        b.position(6);
+
+        ByteBuffer bb = b.slice();
+        checkBuffer(bb);
+
+        assertEquals(0, bb.position());
+        assertEquals(4, bb.limit());
+        assertEquals(4, bb.capacity());
+
+        assertEquals((byte) 0xA6, bb.get());
+        assertEquals((byte) 0xA7, bb.get());
+        assertEquals((byte) 0xA8, bb.get());
+        assertEquals((byte) 0xA9, bb.get());
+        try {
+            bb.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        // Reset position and limit
+        b.position(0);
+        b.limit(b.capacity());
+
+        // Check 'getShort'
+        b.order(ByteOrder.LITTLE_ENDIAN);
+        b.position(0);
+        assertEquals((short) 0xA1A0, b.getShort());
+        assertEquals((short) 0xA3A2, b.getShort());
+        assertEquals((short) 0xA5A4, b.getShort());
+        assertEquals((short) 0xA7A6, b.getShort());
+        assertEquals((short) 0xA9A8, b.getShort());
+        assertEquals((short) 0xABAA, b.getShort());
+        try {
+            bb.getShort();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        b.order(ByteOrder.BIG_ENDIAN);
+        b.position(0);
+        assertEquals((short) 0xA0A1, b.getShort());
+        assertEquals((short) 0xA2A3, b.getShort());
+        assertEquals((short) 0xA4A5, b.getShort());
+        assertEquals((short) 0xA6A7, b.getShort());
+        assertEquals((short) 0xA8A9, b.getShort());
+        assertEquals((short) 0xAAAB, b.getShort());
+        try {
+            bb.getShort();
+           fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        // Check 'getInt'
+        b.order(ByteOrder.LITTLE_ENDIAN);
+        b.position(0);
+        assertEquals(0xA3A2A1A0, b.getInt());
+        assertEquals(0xA7A6A5A4, b.getInt());
+        assertEquals(0xABAAA9A8, b.getInt());
+        try {
+            bb.getInt();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        b.order(ByteOrder.BIG_ENDIAN);
+        b.position(0);
+        assertEquals(0xA0A1A2A3, b.getInt());
+        assertEquals(0xA4A5A6A7, b.getInt());
+        assertEquals(0xA8A9AAAB, b.getInt());
+        try {
+            bb.getInt();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        // Check 'getFloat'
+        b.order(ByteOrder.LITTLE_ENDIAN);
+        b.position(0);
+        assertEquals(0xA3A2A1A0, Float.floatToIntBits(b.getFloat()));
+        assertEquals(0xA7A6A5A4, Float.floatToIntBits(b.getFloat()));
+        assertEquals(0xABAAA9A8, Float.floatToIntBits(b.getFloat()));
+        try {
+            b.getFloat();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        b.order(ByteOrder.BIG_ENDIAN);
+        b.position(0);
+        assertEquals(0xA0A1A2A3, Float.floatToIntBits(b.getFloat()));
+        assertEquals(0xA4A5A6A7, Float.floatToIntBits(b.getFloat()));
+        assertEquals(0xA8A9AAAB, Float.floatToIntBits(b.getFloat()));
+        try {
+            b.getFloat();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        // Check 'getDouble(int position)'
+        b.order(ByteOrder.LITTLE_ENDIAN);
+        assertEquals(0xA7A6A5A4A3A2A1A0L, Double.doubleToLongBits(b.getDouble(0)));
+        assertEquals(0xA8A7A6A5A4A3A2A1L, Double.doubleToLongBits(b.getDouble(1)));
+        try {
+            b.getDouble(-1);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            b.getDouble(5);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        b.order(ByteOrder.BIG_ENDIAN);
+        assertEquals(0xA0A1A2A3A4A5A6A7L, Double.doubleToLongBits(b.getDouble(0)));
+        assertEquals(0xA1A2A3A4A5A6A7A8L, Double.doubleToLongBits(b.getDouble(1)));
+        try {
+            b.getDouble(-1);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            b.getDouble(5);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // Slice and check 'getInt'
+        b.position(1);
+        b.limit(5);
+        b.order(ByteOrder.LITTLE_ENDIAN);
+        bb = b.slice();
+        assertEquals(4, bb.capacity());
+        assertEquals(0xA4A3A2A1, bb.getInt(0));
+
+        bb.order(ByteOrder.LITTLE_ENDIAN);
+        ShortBuffer sb = bb.asShortBuffer();
+
+        checkBuffer(sb);
+        assertEquals(2, sb.capacity());
+        assertEquals((short) 0xA2A1, sb.get());
+        assertEquals((short) 0xA4A3, sb.get());
+
+        bb.order(ByteOrder.BIG_ENDIAN);
+        sb = bb.asShortBuffer();
+
+        checkBuffer(sb);
+        assertEquals(2, sb.capacity());
+        assertEquals((short) 0xA1A2, sb.get());
+        assertEquals((short) 0xA3A4, sb.get());
+
+        bb.order(ByteOrder.LITTLE_ENDIAN);
+        IntBuffer ib = bb.asIntBuffer();
+
+        checkBuffer(ib);
+        assertEquals(1, ib.capacity());
+        assertEquals(0xA4A3A2A1, ib.get());
+
+        bb.order(ByteOrder.BIG_ENDIAN);
+        ib = bb.asIntBuffer();
+
+        checkBuffer(ib);
+        assertEquals(1, ib.capacity());
+        assertEquals(0xA1A2A3A4, ib.get());
+
+        bb.order(ByteOrder.LITTLE_ENDIAN);
+        FloatBuffer fb = bb.asFloatBuffer();
+
+        checkBuffer(fb);
+        assertEquals(1, fb.capacity());
+        assertEquals(0xA4A3A2A1, Float.floatToIntBits(fb.get()));
+
+        bb.order(ByteOrder.BIG_ENDIAN);
+        fb = bb.asFloatBuffer();
+
+        checkBuffer(fb);
+        assertEquals(1, fb.capacity());
+        assertEquals(0xA1A2A3A4, Float.floatToIntBits(fb.get()));
+    }
+
+    private void shortBufferTest(ShortBuffer sb) {
+        checkBuffer(sb);
+
+        try {
+            sb.put(-1, (short) 0);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.put(sb.limit(), (short) 0);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // IndexOutOfBoundsException: offset < 0
+        try {
+            short[] data = new short[8];
+            sb.position(0);
+            sb.put(data, -1, 2);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // IndexOutOfBoundsException: length > array.length - offset
+        try {
+            short[] data = new short[8];
+            sb.position(0);
+            sb.put(data, 1, 8);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // BufferOverflowException: length > remaining()
+        try {
+            short[] data = new short[8];
+            sb.position(sb.limit() - 2);
+            sb.put(data, 0, 3);
+            fail("expected exception not thrown");
+        } catch (BufferOverflowException e) {
+            // expected
+        }
+
+        short[] data = {0, 10, 20, 30, 40, 50, 60, 70};
+        sb.position(0);
+        sb.put(data);
+
+        try {
+            sb.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        sb.position(0);
+        assertEquals((short) 0, sb.get());
+        assertEquals((short) 10, sb.get());
+        assertEquals((short) 20, sb.get());
+        assertEquals((short) 30, sb.get());
+        assertEquals((short) 40, sb.get());
+        assertEquals((short) 50, sb.get());
+        assertEquals((short) 60, sb.get());
+        assertEquals((short) 70, sb.get());
+        try {
+            sb.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+        sb.position(1);
+        sb.put((short) 11);
+        assertEquals((short) 11, sb.get(1));
+
+        short[] ss1 = {33, 44, 55, 66};
+        sb.position(3);
+        sb.put(ss1);
+        sb.position(0);
+        assertEquals((short) 0, sb.get());
+        assertEquals((short) 11, sb.get());
+        assertEquals((short) 20, sb.get());
+        assertEquals((short) 33, sb.get());
+        assertEquals((short) 44, sb.get());
+        assertEquals((short) 55, sb.get());
+        assertEquals((short) 66, sb.get());
+        assertEquals((short) 70, sb.get());
+
+        short[] ss2 = {10, 22, 30};
+        sb.position(2);
+        sb.put(ss2, 1, 1);
+        sb.position(0);
+        assertEquals((short) 0, sb.get());
+        assertEquals((short) 11, sb.get());
+        assertEquals((short) 22, sb.get());
+        assertEquals((short) 33, sb.get());
+        assertEquals((short) 44, sb.get());
+        assertEquals((short) 55, sb.get());
+        assertEquals((short) 66, sb.get());
+        assertEquals((short) 70, sb.get());
+    }
+
+    private void intBufferTest(IntBuffer ib) {
+        checkBuffer(ib);
+
+        try {
+            ib.put(-1, (int) 0);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            ib.put(ib.limit(), (int) 0);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // IndexOutOfBoundsException: offset < 0
+        try {
+            int[] data = new int[8];
+            ib.position(0);
+            ib.put(data, -1, 2);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // IndexOutOfBoundsException: length > array.length - offset
+        try {
+            int[] data = new int[8];
+            ib.position(0);
+            ib.put(data, 1, 8);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // BufferOverflowException: length > remaining()
+        try {
+            int[] data = new int[8];
+            ib.position(ib.limit() - 2);
+            ib.put(data, 0, 3);
+            fail("expected exception not thrown");
+        } catch (BufferOverflowException e) {
+            // expected
+        }
+
+        int[] data = {0, 10, 20, 30, 40, 50, 60, 70};
+        ib.position(0);
+        ib.put(data);
+
+        try {
+            ib.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        ib.position(0);
+        assertEquals((int) 0, ib.get());
+        assertEquals((int) 10, ib.get());
+        assertEquals((int) 20, ib.get());
+        assertEquals((int) 30, ib.get());
+        assertEquals((int) 40, ib.get());
+        assertEquals((int) 50, ib.get());
+        assertEquals((int) 60, ib.get());
+        assertEquals((int) 70, ib.get());
+        try {
+            ib.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+        ib.position(1);
+        ib.put((int) 11);
+        assertEquals((int) 11, ib.get(1));
+
+        int[] ss1 = {33, 44, 55, 66};
+        ib.position(3);
+        ib.put(ss1);
+        ib.position(0);
+        assertEquals((int) 0, ib.get());
+        assertEquals((int) 11, ib.get());
+        assertEquals((int) 20, ib.get());
+        assertEquals((int) 33, ib.get());
+        assertEquals((int) 44, ib.get());
+        assertEquals((int) 55, ib.get());
+        assertEquals((int) 66, ib.get());
+        assertEquals((int) 70, ib.get());
+
+        int[] ss2 = {10, 22, 30};
+        ib.position(2);
+        ib.put(ss2, 1, 1);
+        ib.position(0);
+        assertEquals((int) 0, ib.get());
+        assertEquals((int) 11, ib.get());
+        assertEquals((int) 22, ib.get());
+        assertEquals((int) 33, ib.get());
+        assertEquals((int) 44, ib.get());
+        assertEquals((int) 55, ib.get());
+        assertEquals((int) 66, ib.get());
+        assertEquals((int) 70, ib.get());
+    }
+
+    void floatBufferTest(FloatBuffer fb) {
+        checkBuffer(fb);
+
+        try {
+            fb.put(-1, (float) 0);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            fb.put(fb.limit(), (float) 0);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // IndexOutOfBoundsException: offset < 0
+        try {
+            float[] data = new float[8];
+            fb.position(0);
+            fb.put(data, -1, 2);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // IndexOutOfBoundsException: length > array.length - offset
+        try {
+            float[] data = new float[8];
+            fb.position(0);
+            fb.put(data, 1, 8);
+            fail("expected exception not thrown");
+        } catch (IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        // BufferOverflowException: length > remaining()
+        try {
+            float[] data = new float[8];
+            fb.position(fb.limit() - 2);
+            fb.put(data, 0, 3);
+            fail("expected exception not thrown");
+        } catch (BufferOverflowException e) {
+            // expected
+        }
+
+        float[] data = {0, 10, 20, 30, 40, 50, 60, 70};
+        fb.position(0);
+        fb.put(data);
+
+        try {
+            fb.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+
+        fb.position(0);
+        assertEquals((float) 0, fb.get());
+        assertEquals((float) 10, fb.get());
+        assertEquals((float) 20, fb.get());
+        assertEquals((float) 30, fb.get());
+        assertEquals((float) 40, fb.get());
+        assertEquals((float) 50, fb.get());
+        assertEquals((float) 60, fb.get());
+        assertEquals((float) 70, fb.get());
+        try {
+            fb.get();
+            fail("expected exception not thrown");
+        } catch (BufferUnderflowException e) {
+            // expected
+        }
+        fb.position(1);
+        fb.put((float) 11);
+        assertEquals((float) 11, fb.get(1));
+
+        float[] ss1 = {33, 44, 55, 66};
+        fb.position(3);
+        fb.put(ss1);
+        fb.position(0);
+        assertEquals((float) 0, fb.get());
+        assertEquals((float) 11, fb.get());
+        assertEquals((float) 20, fb.get());
+        assertEquals((float) 33, fb.get());
+        assertEquals((float) 44, fb.get());
+        assertEquals((float) 55, fb.get());
+        assertEquals((float) 66, fb.get());
+        assertEquals((float) 70, fb.get());
+
+        float[] ss2 = {10, 22, 30};
+        fb.position(2);
+        fb.put(ss2, 1, 1);
+        fb.position(0);
+        assertEquals((float) 0, fb.get());
+        assertEquals((float) 11, fb.get());
+        assertEquals((float) 22, fb.get());
+        assertEquals((float) 33, fb.get());
+        assertEquals((float) 44, fb.get());
+        assertEquals((float) 55, fb.get());
+        assertEquals((float) 66, fb.get());
+        assertEquals((float) 70, fb.get());
+    }
+}
diff --git a/tests/CoreTests/android/core/OutputStreamWriterTest.java b/tests/CoreTests/android/core/OutputStreamWriterTest.java
new file mode 100644
index 0000000..1c0901e
--- /dev/null
+++ b/tests/CoreTests/android/core/OutputStreamWriterTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests basic functionality of an OutputStreamWriter.
+ */
+public class OutputStreamWriterTest extends TestCase {
+    
+    @SmallTest
+    public void testOutputStreamWriter() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        ByteArrayOutputStream aa = new ByteArrayOutputStream();
+        OutputStreamWriter a = new OutputStreamWriter(aa, "ISO8859_1");
+        try {
+            a.write(str, 0, 4);
+            a.write('A');
+            // We have to flush the OutputStreamWriter to guarantee
+            // that the results will appear in the underlying OutputStream
+            a.flush();
+            assertEquals("ISO8859_1", a.getEncoding());
+            assertEquals(5, aa.size());
+            assertEquals("AbCdA", aa.toString());
+        } finally {
+            a.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/ParseIntTest.java b/tests/CoreTests/android/core/ParseIntTest.java
new file mode 100644
index 0000000..0e3b0c6
--- /dev/null
+++ b/tests/CoreTests/android/core/ParseIntTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for functionality of class Integer to parse integers.
+ */
+public class ParseIntTest extends TestCase {
+    
+    @SmallTest
+    public void testParseInt() throws Exception {
+        assertEquals(0, Integer.parseInt("0", 10));
+        assertEquals(473, Integer.parseInt("473", 10));
+        assertEquals(0, Integer.parseInt("-0", 10));
+        assertEquals(-255, Integer.parseInt("-FF", 16));
+        assertEquals(102, Integer.parseInt("1100110", 2));
+        assertEquals(2147483647, Integer.parseInt("2147483647", 10));
+        assertEquals(-2147483648, Integer.parseInt("-2147483648", 10));
+
+        try {
+            Integer.parseInt("2147483648", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        try {
+            Integer.parseInt("-2147483649", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        // One digit too many
+        try {
+            Integer.parseInt("21474836470", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        try {
+            Integer.parseInt("-21474836480", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        try {
+            Integer.parseInt("21474836471", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        try {
+            Integer.parseInt("-21474836481", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        try {
+            Integer.parseInt("214748364710", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        try {
+            Integer.parseInt("-214748364811", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        try {
+            Integer.parseInt("99", 8);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        try {
+            Integer.parseInt("Kona", 10);
+            fail();
+        } catch (NumberFormatException e) {
+            // ok
+        }
+
+        assertEquals(411787, Integer.parseInt("Kona", 27));
+    }
+}
diff --git a/tests/CoreTests/android/core/PipedStreamTest.java b/tests/CoreTests/android/core/PipedStreamTest.java
new file mode 100644
index 0000000..564b337
--- /dev/null
+++ b/tests/CoreTests/android/core/PipedStreamTest.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+class Fibonacci {
+    int n1 = -1;
+    int n2;
+
+    public int next() {
+        if (n1 < 0) {
+            n1 = 0;
+            return 0;
+        } else if (n1 == 0) {
+            n2 = 0;
+            n1 = 1;
+            return 1;
+        } else {
+            int ret = n1 + n2;
+            n2 = n1;
+            n1 = ret;
+            return ret;
+        }
+    }
+}
+
+
+public class PipedStreamTest extends TestCase {
+
+    private abstract static class TestThread extends Thread {
+        public abstract void runTest() throws Exception;
+
+        public final void run() {
+            try {
+                runTest();
+            } catch (Throwable e) {
+                android.util.Log.e("PST", "Got exception " + e, e);
+                android.util.Log.e("PST", android.util.Log.getStackTraceString(e));
+                exception = e;
+            }
+        }
+
+        Throwable exception;
+        int countRead = 0;
+    }
+
+    @MediumTest
+    public void testA() throws Exception {
+
+        final PipedInputStream in = new PipedInputStream();
+        final PipedOutputStream out = new PipedOutputStream(in);
+
+        assertEquals(0, in.available());
+
+        TestThread reader, writer;
+
+        reader = new TestThread() {
+            Fibonacci fib = new Fibonacci();
+
+            @Override
+            public void runTest() throws Exception {
+                int readInt;
+                byte readByte;
+
+                for (; ;) {
+                    readInt = in.read();
+
+                    if (readInt == -1) {
+                        return;
+                    }
+
+                    readByte = (byte) readInt;
+                    assertEquals(readByte, (byte) fib.next());
+                    countRead++;
+                }
+            }
+        };
+
+        reader.start();
+
+        writer = new TestThread() {
+            Fibonacci fib = new Fibonacci();
+
+            @Override
+            public void runTest() throws Exception {
+                for (int i = 0; i < 2000; i++) {
+                    int toWrite = fib.next();
+                    out.write(toWrite);
+                }
+                out.close();
+            }
+        };
+
+        writer.start();
+
+
+        for (; ;) {
+            try {
+                reader.join(60 * 1000);
+                writer.join(1 * 1000);
+                break;
+            } catch (InterruptedException ex) {
+            }
+        }
+
+        assertEquals(2000, reader.countRead);
+
+        if (writer.exception != null) {
+            throw new Exception(writer.exception);
+        }
+        if (reader.exception != null) {
+            throw new Exception(reader.exception);
+        }
+    }
+
+    @MediumTest
+    public void testB() throws Exception {
+        final PipedInputStream in = new PipedInputStream();
+        final PipedOutputStream out = new PipedOutputStream(in);
+
+        assertEquals(0, in.available());
+
+        TestThread reader, writer;
+
+        reader = new TestThread() {
+            Fibonacci fib = new Fibonacci();
+
+            @Override
+            public void runTest() throws Exception {
+                byte readBytes[] = new byte[5];
+                int ret;
+
+                for (; ;) {
+                    int nread = 0;
+                    while (nread < 5) {
+                        ret = in.read(readBytes, nread, readBytes.length - nread);
+
+                        if (ret == -1) {
+                            return;
+                        }
+                        nread += ret;
+                    }
+
+                    assertEquals(5, nread);
+
+                    int readInt = (((int) readBytes[0] & 0xff) << 24)
+                            | (((int) readBytes[1] & 0xff) << 16)
+                            | (((int) readBytes[2] & 0xff) << 8)
+                            | (((int) readBytes[3] & 0xff) << 0);
+
+
+                    assertEquals(readInt, fib.next());
+                    assertEquals(0, readBytes[4]);
+                    countRead++;
+                }
+            }
+        };
+
+        reader.start();
+
+        writer = new TestThread() {
+            Fibonacci fib = new Fibonacci();
+
+            @Override
+            public void runTest() throws Exception {
+                byte writeBytes[] = new byte[5];
+                for (int i = 0; i < 2000; i++) {
+                    int toWrite = fib.next();
+                    writeBytes[0] = (byte) (toWrite >> 24);
+                    writeBytes[1] = (byte) (toWrite >> 16);
+                    writeBytes[2] = (byte) (toWrite >> 8);
+                    writeBytes[3] = (byte) (toWrite >> 0);
+                    writeBytes[4] = 0;
+                    out.write(writeBytes, 0, writeBytes.length);
+                }
+                out.close();
+            }
+        };
+
+        writer.start();
+
+
+        for (; ;) {
+            try {
+                reader.join(60 * 1000);
+                writer.join(1 * 1000);
+                break;
+            } catch (InterruptedException ex) {
+            }
+        }
+
+        assertEquals(2000, reader.countRead);
+
+        if (writer.exception != null) {
+            throw new Exception(writer.exception);
+        }
+        if (reader.exception != null) {
+            throw new Exception(reader.exception);
+        }
+    }
+
+    @SmallTest
+    public void testC() throws Exception {
+        final PipedInputStream in = new PipedInputStream();
+        final PipedOutputStream out = new PipedOutputStream(in);
+
+        assertEquals(0, in.available());
+
+        TestThread reader, writer;
+
+        reader = new TestThread() {
+            Fibonacci fib = new Fibonacci();
+
+            @Override
+            public void runTest() throws Exception {
+                byte readBytes[] = new byte[1024 * 2];
+                int ret;
+
+                for (; ;) {
+                    int nread = 0;
+                    while (nread < readBytes.length) {
+                        ret = in.read(readBytes, nread, readBytes.length - nread);
+
+                        if (ret == -1) {
+                            return;
+                        }
+                        nread += ret;
+                    }
+
+                    assertEquals(nread, readBytes.length);
+
+                    for (int i = 0; i < (readBytes.length - 4); i += 4) {
+                        int readInt = (((int) readBytes[i + 0] & 0xff) << 24)
+                                | (((int) readBytes[i + 1] & 0xff) << 16)
+                                | (((int) readBytes[i + 2] & 0xff) << 8)
+                                | (((int) readBytes[i + 3] & 0xff) << 0);
+
+                        assertEquals(readInt, fib.next());
+                    }
+                }
+            }
+        };
+
+        reader.start();
+
+        writer = new TestThread() {
+            Fibonacci fib = new Fibonacci();
+
+            @Override
+            public void runTest() throws Exception {
+                byte writeBytes[] = new byte[1024 * 2];
+                for (int i = 0; i < (writeBytes.length - 4); i += 4) {
+                    int toWrite = fib.next();
+                    writeBytes[i + 0] = (byte) (toWrite >> 24);
+                    writeBytes[i + 1] = (byte) (toWrite >> 16);
+                    writeBytes[i + 2] = (byte) (toWrite >> 8);
+                    writeBytes[i + 3] = (byte) (toWrite >> 0);
+                }
+                out.write(writeBytes, 0, writeBytes.length);
+                out.close();
+            }
+        };
+
+        writer.start();
+
+
+        for (; ;) {
+            try {
+                reader.join(60 * 1000);
+                writer.join(1 * 100);
+                break;
+            } catch (InterruptedException ex) {
+            }
+        }
+
+        if (writer.exception != null) {
+            throw new Exception(writer.exception);
+        }
+        if (reader.exception != null) {
+            throw new Exception(reader.exception);
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/PrintWriterTest.java b/tests/CoreTests/android/core/PrintWriterTest.java
new file mode 100644
index 0000000..09ee389
--- /dev/null
+++ b/tests/CoreTests/android/core/PrintWriterTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class PrintWriterTest extends TestCase {
+
+    @SmallTest
+    public void testPrintWriter() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        StringWriter aa = new StringWriter();
+        PrintWriter a = new PrintWriter(aa);
+
+        try {
+            a.write(str, 0, 26);
+            a.write('X');
+
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", aa.toString());
+
+            a.write("alphabravodelta", 5, 5);
+            a.append('X');
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", aa.toString());
+            a.append("omega");
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", aa.toString());
+            a.print("ZZZ");
+            assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomegaZZZ", aa.toString());
+        } finally {
+            a.close();
+        }
+
+        StringWriter ba = new StringWriter();
+        PrintWriter b = new PrintWriter(ba);
+        try {
+            b.print(true);
+            b.print((char) 'A');
+            b.print("BCD".toCharArray());
+            b.print((double) 1.2);
+            b.print((float) 3);
+            b.print((int) 4);
+            b.print((long) 5);
+            assertEquals("trueABCD1.23.045", ba.toString());
+            b.println();
+            b.println(true);
+            b.println((char) 'A');
+            b.println("BCD".toCharArray());
+            b.println((double) 1.2);
+            b.println((float) 3);
+            b.println((int) 4);
+            b.println((long) 5);
+            b.print("THE END");
+            assertEquals("trueABCD1.23.045\ntrue\nA\nBCD\n1.2\n3.0\n4\n5\nTHE END", ba.toString());
+        } finally {
+            b.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/PushbackInputStreamTest.java b/tests/CoreTests/android/core/PushbackInputStreamTest.java
new file mode 100644
index 0000000..44cfd8a
--- /dev/null
+++ b/tests/CoreTests/android/core/PushbackInputStreamTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.PushbackInputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class PushbackInputStreamTest extends TestCase {
+
+    @SmallTest
+    public void testPushbackInputStream() throws Exception {
+        String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz";
+        ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes());
+        ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes());
+
+        PushbackInputStream a = new PushbackInputStream(aa, 7);
+        try {
+            a.unread("push".getBytes());
+            assertEquals("pushAbCdEfGhIjKlM\nOpQrStUvWxYz", IOUtil.read(a));
+        } finally {
+            a.close();
+        }
+
+        PushbackInputStream b = new PushbackInputStream(ba, 9);
+        try {
+            b.unread('X');
+            assertEquals("XAbCdEfGhI", IOUtil.read(b, 10));
+        } finally {
+            b.close();
+        }
+
+        PushbackInputStream c = new PushbackInputStream(ca);
+        try {
+            assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c));
+        } finally {
+            c.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/PushbackReaderTest.java b/tests/CoreTests/android/core/PushbackReaderTest.java
new file mode 100644
index 0000000..ef62c28
--- /dev/null
+++ b/tests/CoreTests/android/core/PushbackReaderTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.PushbackReader;
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class PushbackReaderTest extends TestCase {
+
+    @SmallTest
+    public void testPushbackReader() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        StringReader aa = new StringReader(str);
+        StringReader ba = new StringReader(str);
+        StringReader ca = new StringReader(str);
+
+        PushbackReader a = new PushbackReader(aa, 5);
+        try {
+            a.unread("PUSH".toCharArray());
+            assertEquals("PUSHAbCdEfGhIjKlMnOpQrStUvWxYz", IOUtil.read(a));
+        } finally {
+            a.close();
+        }
+
+        PushbackReader b = new PushbackReader(ba, 15);
+        try {
+            b.unread('X');
+            assertEquals("XAbCdEfGhI", IOUtil.read(b, 10));
+        } finally {
+            b.close();
+        }
+
+        PushbackReader c = new PushbackReader(ca);
+        try {
+            assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+        } finally {
+            c.close();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/ReflectArrayTest.java b/tests/CoreTests/android/core/ReflectArrayTest.java
new file mode 100644
index 0000000..20ee8a4
--- /dev/null
+++ b/tests/CoreTests/android/core/ReflectArrayTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Array;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Test java.lang.reflect.Array methods.
+ */
+public class ReflectArrayTest extends TestCase {
+
+    @SmallTest
+    public void testSingleInt() throws Exception {
+        Object intArray = Array.newInstance(Integer.TYPE, 2);
+
+        int[] array = (int[]) intArray;
+        array[0] = 5;
+        Array.setInt(intArray, 1, 6);
+
+        assertEquals(5, Array.getInt(intArray, 0));
+        assertEquals(6, array[1]);
+
+        try {
+            array[2] = 27;
+            fail("store should have failed");
+        } catch (ArrayIndexOutOfBoundsException abe) {
+            // expected
+        }
+
+        assertEquals(2, array.length);
+        assertEquals(Array.getLength(intArray), array.length);
+
+        try {
+            int[][] wrongArray = (int[][]) intArray;
+            fail("cast should have failed");
+        } catch (ClassCastException cce) {
+            // expected
+        }
+
+        intArray = Array.newInstance(Integer.TYPE, 0);
+        assertEquals(0, Array.getLength(intArray));
+    }
+
+    @SmallTest
+    public void testSingle() throws Exception {
+        Object strArray = Array.newInstance(String.class, 2);
+
+        String[] array = (String[]) strArray;
+        array[0] = "entry zero";
+        Array.set(strArray, 1, "entry one");
+
+        //System.out.println("array: " + array);
+
+        assertEquals("entry zero", Array.get(strArray, 0));
+        assertEquals("entry one", array[1]);
+
+        assertEquals(2, array.length);
+        assertEquals(Array.getLength(strArray), array.length);
+    }
+
+    @SmallTest
+    public void testMultiInt() throws Exception {
+        int[] dimensions = {3, 2, 1};
+        Object intIntIntArray = Array.newInstance(Integer.TYPE, dimensions);
+        int[][][] array3 = (int[][][]) intIntIntArray;
+
+        array3[0][0][0] = 123;
+        array3[2][1][0] = 456;
+
+        try {
+            array3[2][1][1] = 768;
+            fail("store should have failed");
+        } catch (ArrayIndexOutOfBoundsException abe) {
+            // expected
+        }
+
+        //System.out.println("array3: " + array3);
+    }
+
+    @SmallTest
+    public void testMulti() throws Exception {
+        int[] dimensions = {1, 2, 3};
+        Object strStrStrArray = Array.newInstance(String.class, dimensions);
+        String[][][] array3 = (String[][][]) strStrStrArray;
+
+        array3[0][0][0] = "zero zero zero";
+        array3[0][1][2] = "zero one two";
+
+        try {
+            array3[1][0][0] = "bad store";
+            fail("store should have failed");
+        } catch (ArrayIndexOutOfBoundsException abe) {
+            // expected
+        }
+
+        try {
+            String[][] array2 = (String[][]) strStrStrArray;
+            fail("expecting bad cast");
+        } catch (ClassCastException cce) {
+            // expected
+        }
+        //System.out.println("array3: " + array3);
+
+
+        int[] dimensions2 = {1, 2};
+        strStrStrArray = Array.newInstance(String[].class, dimensions2);
+        array3 = (String[][][]) strStrStrArray;
+        array3[0][1] = new String[3];
+        array3[0][1][2] = "zero one two";
+        try {
+            array3[1][0][0] = "bad store";
+            fail("store should have failed");
+        } catch (ArrayIndexOutOfBoundsException abe) {
+            // expected
+        }
+        //System.out.println("array3: " + array3);
+    }
+}
+
diff --git a/tests/CoreTests/android/core/RegexTest.java b/tests/CoreTests/android/core/RegexTest.java
new file mode 100644
index 0000000..a7f79e8
--- /dev/null
+++ b/tests/CoreTests/android/core/RegexTest.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.util.Regex;
+
+import junit.framework.TestCase;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Tests basic functionality of Pattern and Matcher classes.
+ */
+public class RegexTest extends TestCase {
+
+    @SmallTest
+    public void testMatches() throws Exception {
+        /* Tests class Matcher */
+
+        Pattern p = Pattern.compile("bcd");
+        Matcher m = p.matcher("bcd");
+        assertTrue("Should match.", m.matches());
+
+        /* Pattern in the middle */
+        p = Pattern.compile("bcd");
+        m = p.matcher("abcdefg");
+        assertFalse("Should not match.", m.matches());
+
+        /* Pattern at the head */
+        m = p.matcher("bcdefg");
+        assertFalse("Should not match.", m.matches());
+
+        /* Pattern at the tail */
+        m = p.matcher("abcd");
+        assertFalse("Should not match.", m.matches());
+
+        /* Make sure matches() doesn't change after calls to find() */
+        p = Pattern.compile(".*");
+        m = p.matcher("abc");
+        assertTrue(m.matches());
+        assertTrue(m.find());
+        assertTrue(m.matches());
+
+        p = Pattern.compile(".");
+        m = p.matcher("abc");
+        assertFalse(m.matches());
+        assertTrue(m.find());
+        assertFalse(m.matches());
+
+        /* Make sure matches() agrees after a reset() */
+        m.reset("z");
+        assertTrue(m.matches());
+
+        m.reset("xyz");
+        assertFalse(m.matches());
+
+        /* Tests class Pattern */
+
+        assertFalse("Erroneously matched partial string.  " +
+                "See http://b/issue?id=754601", Pattern.matches("er", "xer"));
+        assertFalse("Erroneously matched partial string.  " +
+                "See http://b/issue?id=754601", Pattern.matches("xe", "xer"));
+        assertTrue("Generic regex should match.",
+                Pattern.matches(".*", "bcd"));
+        assertTrue("Grouped regex should match.",
+                Pattern.matches("(b(c(d)))", "bcd"));
+        assertTrue("Grouped regex should match.",
+                Pattern.matches("(b)(c)(d)", "bcd"));
+    }
+
+    @SmallTest
+    public void testGroupCount() throws Exception {
+        Pattern p = Pattern.compile(
+                "\\b(?:\\+?1)?"
+                        + "(?:[ -\\.])?"
+                        + "\\(?(\\d{3})?\\)?"
+                        + "(?:[ -\\.\\/])?"
+                        + "(\\d{3})"
+                        + "(?:[ -\\.])?"
+                        + "(\\d{4})\\b"
+        );
+
+        Matcher m = p.matcher("1 (919) 555-1212");
+
+        assertEquals("groupCount is incorrect, see http://b/issue?id=759412",
+                3, m.groupCount());
+    }
+
+    @SmallTest
+    public void testGroups() throws Exception {
+        Pattern p = Pattern.compile("(b)([c|d])(z*)");
+        Matcher m = p.matcher("abcdefg");
+
+        /* Must call find() first, otherwise group*() are undefined. */
+        assertTrue(m.find());
+
+        assertEquals(3, m.groupCount());
+
+        assertEquals("bc", m.group(0));
+        assertEquals("b", m.group(1));
+        assertEquals("c", m.group(2));
+        assertEquals("", m.group(3));
+    }
+
+    @SmallTest
+    public void testFind() throws Exception {
+        Pattern p = Pattern.compile(".");
+        Matcher m = p.matcher("abc");
+
+        assertTrue(m.find());
+        assertEquals("a", m.group(0));
+
+        assertTrue(m.find());
+        assertEquals("b", m.group(0));
+
+        assertTrue(m.find());
+        assertEquals("c", m.group(0));
+
+        assertFalse(m.find());
+    }
+
+    @SmallTest
+    public void testReplaceAll() throws Exception {
+        // Begins with non-matching text, ends with matching text
+        Pattern p = Pattern.compile("a*b");
+        Matcher m = p.matcher("fooaabfooaabfooabfoob");
+
+        String r = m.replaceAll("-");
+        assertEquals("foo-foo-foo-foo-", r);
+
+        // Begins with matching text, ends with non-matching text
+        p = Pattern.compile("a*b");
+        m = p.matcher("aabfooaabfooabfoobfoo");
+
+        r = m.replaceAll("-");
+        assertEquals("-foo-foo-foo-foo", r);
+    }
+
+    @SmallTest
+    public void testReplaceFirst() throws Exception {
+        // Begins with non-matching text, ends with matching text
+        Pattern p = Pattern.compile("a*b");
+        Matcher m = p.matcher("fooaabfooaabfooabfoob");
+
+        String r = m.replaceFirst("-");
+        assertEquals("foo-fooaabfooabfoob", r);
+
+        // Begins with matching text, ends with non-matching text
+        p = Pattern.compile("a*b");
+        m = p.matcher("aabfooaabfooabfoobfoo");
+
+        r = m.replaceFirst("-");
+        assertEquals("-fooaabfooabfoobfoo", r);
+    }
+
+    @SmallTest
+    public void testSplit() throws Exception {
+        Pattern p = Pattern.compile(":");
+        String[] strings;
+
+        strings = p.split("boo:and:foo");
+        assertEquals(3, strings.length);
+        assertEquals("boo", strings[0]);
+        assertEquals("and", strings[1]);
+        assertEquals("foo", strings[2]);
+
+        strings = p.split("boo:and:foo", 2);
+        assertEquals(2, strings.length);
+        assertEquals("boo", strings[0]);
+        assertEquals("and:foo", strings[1]);
+
+        strings = p.split("boo:and:foo", 5);
+        assertEquals(3, strings.length);
+        assertEquals("boo", strings[0]);
+        assertEquals("and", strings[1]);
+        assertEquals("foo", strings[2]);
+
+        strings = p.split("boo:and:foo", -2);
+        assertEquals(3, strings.length);
+        assertEquals("boo", strings[0]);
+        assertEquals("and", strings[1]);
+        assertEquals("foo", strings[2]);
+
+        p = Pattern.compile("o");
+
+        strings = p.split("boo:and:foo");
+        assertEquals(3, strings.length);
+        assertEquals("b", strings[0]);
+        assertEquals("", strings[1]);
+        assertEquals(":and:f", strings[2]);
+
+        strings = p.split("boo:and:foo", 5);
+        assertEquals(5, strings.length);
+        assertEquals("b", strings[0]);
+        assertEquals("", strings[1]);
+        assertEquals(":and:f", strings[2]);
+        assertEquals("", strings[3]);
+        assertEquals("", strings[4]);
+
+        strings = p.split("boo:and:foo", -2);
+        assertEquals(5, strings.length);
+        assertEquals("b", strings[0]);
+        assertEquals("", strings[1]);
+        assertEquals(":and:f", strings[2]);
+        assertEquals("", strings[3]);
+        assertEquals("", strings[4]);
+
+        strings = p.split("boo:and:foo", 0);
+        assertEquals(3, strings.length);
+        assertEquals("b", strings[0]);
+        assertEquals("", strings[1]);
+        assertEquals(":and:f", strings[2]);
+    }
+    
+    // -------------------------------------------------------------------
+    // Regression test for #1172774: Bug in Regex.java
+    // Regression test for #1216887: Regular expression match is very slow
+    public static final Pattern TOP_LEVEL_DOMAIN_PATTERN = Pattern.compile(
+            "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+            + "|(biz|b[abdefghijmnorstvwyz])"
+            + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
+            + "|d[ejkmoz]"
+            + "|(edu|e[cegrstu])"
+            + "|f[ijkmor]"
+            + "|(gov|g[abdefghilmnpqrstuwy])"
+            + "|h[kmnrtu]"
+            + "|(info|int|i[delmnoqrst])"
+            + "|(jobs|j[emop])"
+            + "|k[eghimnrwyz]"
+            + "|l[abcikrstuvy]"
+            + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
+            + "|(name|net|n[acefgilopruz])"
+            + "|(org|om)"
+            + "|(pro|p[aefghklmnrstwy])"
+            + "|qa"
+            + "|r[eouw]"
+            + "|s[abcdeghijklmnortuvyz]"
+            + "|(tel|travel|t[cdfghjklmnoprtvwz])"
+            + "|u[agkmsyz]"
+            + "|v[aceginu]"
+            + "|w[fs]"
+            + "|y[etu]"
+            + "|z[amw])");
+
+    public static final Pattern EMAIL_ADDRESS_PATTERN = Pattern.compile(
+            "[\\+a-zA-Z0-9\\.\\_\\%\\-]+\\@" 
+            + "(("
+            + "[a-zA-Z0-9]\\.|"
+            + "([a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9]\\.)+)"
+            + TOP_LEVEL_DOMAIN_PATTERN
+            + ")");
+    
+    @SmallTest
+    public void testMonsterRegexCorrectness() {
+        assertTrue(EMAIL_ADDRESS_PATTERN.matcher("a+b@gmail.com").matches());        
+    }
+
+    @SmallTest
+    public void testMonsterRegexPerformance() {
+        android.util.Log.e("RegexTest", "RegEx performance test started.");
+        long t0 = System.currentTimeMillis();
+        Matcher m = EMAIL_ADDRESS_PATTERN.matcher("donot repeate@RC8jjjjjjjjjjjjjjj");
+        assertFalse(m.find());
+        long t1 = System.currentTimeMillis();
+        android.util.Log.e("RegexTest", "RegEx performance test finished, " +
+                "took " + (t1 - t0) + " ms.");
+    }
+
+    //
+    // -------------------------------------------------------------------
+    
+}
diff --git a/tests/CoreTests/android/core/RequestAPITest.java b/tests/CoreTests/android/core/RequestAPITest.java
new file mode 100644
index 0000000..d89f5ae
--- /dev/null
+++ b/tests/CoreTests/android/core/RequestAPITest.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+import android.net.http.RequestHandle;
+import android.net.http.RequestQueue;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+import android.webkit.CookieSyncManager;
+import com.google.android.collect.Maps;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Container class for all RequestAPI tests
+ */
+//http://b/issue?id=1200337
+@Suppress
+public class RequestAPITest extends AndroidTestCase implements HttpConstants {
+    private static final String LOGTAG = "http";
+
+    /*
+      Other tests to write
+      GET, HEAD, POST with differing parameters to RequestQueue
+      More reuse and pipelining tests - testing for server closing unexpectedly
+    */
+
+    // Sync object for synchronizing end of each test that does communications
+    public static Object syncObj = new Object();
+
+    private RequestQueue mRequestQueue;
+    private TestWebServer mTestWebServer;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        Log.d(LOGTAG, "Base setup context = " + mContext);
+        mRequestQueue = new RequestQueue(mContext);
+        CookieSyncManager.createInstance(mContext);
+
+        mTestWebServer = new TestWebServer();
+        mTestWebServer.initServer(8080, true);
+    }
+
+    protected void tearDown() throws Exception {
+        Log.d(LOGTAG, "Base tearDown");
+        mTestWebServer.close();
+        Log.d(LOGTAG, "Base teardown done");
+
+        super.tearDown();
+    }
+
+    public void verifyFailure(Map<String, String> headers) {
+        try {
+            RequestHandle handle =
+                    mRequestQueue.queueRequest(
+                            "http://localhost:8080/test1", "GET", headers, null,
+                            null, 0, false);
+
+            handle.waitUntilComplete();
+            fail("expected exception not thrown");
+        } catch (RuntimeException e) {
+            // expected
+        }
+    }
+
+    public void testRequestAddNullHeader() throws Exception {
+        /**
+         * Test Request.addHeader throws a NullPointerException if a null
+         * header is attempted to be set
+         */
+        Log.d(LOGTAG, "testRequestAddNullHeader start ");
+        Map<String, String> headers = Maps.newHashMap();
+        headers.put(null, null);
+        verifyFailure(headers);
+        Log.d(LOGTAG, "testRequestAddNullHeader - returning");
+    }
+
+    public void testRequestAddNullValue() throws Exception {
+        /**
+         * Test Request.addHeader throws a RuntimeException if a null
+         * value is attempted to be set
+         */
+        Log.d(LOGTAG, "testRequestAddNullValue start ");
+        Map<String, String> headers = Maps.newHashMap();
+        headers.put("TestHeader", null);
+        verifyFailure(headers);
+        Log.d(LOGTAG, "testRequestAddNullValue - returning");
+    }
+
+    public void testRequestAddEmptyValue() throws Exception {
+        /**
+         * Test Request.addEmptyValue throws a RuntimeException if an empty
+         * header is attempted to be set
+         */
+        Log.d(LOGTAG, "testRequestAddEmptyValue start ");
+        Map<String, String> headers = Maps.newHashMap();
+        headers.put("TestHeader", "");
+        verifyFailure(headers);
+        Log.d(LOGTAG, "testRequestAddEmptyValue - returning");
+    }
+
+    public void verifySuccess(Map<String, String> headers) {
+        mTestWebServer.setKeepAlive(false);
+        RequestHandle handle = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "GET", headers, null,
+                null, 0, false);
+        handle.waitUntilComplete();
+    }
+
+    public void testRequestAddHeader() throws Exception {
+        /**
+         * Test Request.addHeader with a valid header and value can be set without
+         * generating and exception
+         */
+        Log.d(LOGTAG, "testRequestAddHeader start ");
+        Map<String, String> headers = Maps.newHashMap();
+        headers.put("TestHeader", "RequestAddHeader");
+        verifySuccess(headers);
+        Log.d(LOGTAG, "testRequestAddHeader - returning");
+    }
+
+    public void testRequestAddMultiHeader() throws Exception {
+        /**
+         * Test multiple calls to Request.addHeader with valid headers and values
+         * can be set without generating and exception
+         */
+        Log.d(LOGTAG, "testRequestAddMultiHeader start ");
+        Map<String, String> headers = Maps.newHashMap();
+        headers.put("TestHeader", "RequestAddMultiHeader");
+        headers.put("TestHeader2", "RequestAddMultiHeader");
+        headers.put("TestHeader3", "RequestAddMultiHeader");
+        verifySuccess(headers);
+        Log.d(LOGTAG, "testRequestAddMultiHeader - returning");
+    }
+
+    public void testRequestAddSameHeader() throws Exception {
+        /**
+         * Test multiple calls to Request.addHeader with valid identical headers
+         * and values can be set without generating and exception
+         */
+        Log.d(LOGTAG, "testRequestAddSameHeader start ");
+        Map<String, String> headers = Maps.newHashMap();
+        headers.put("TestHeader", "RequestAddSameHeader");
+        headers.put("TestHeader", "RequestAddSameHeader");
+        headers.put("TestHeader", "RequestAddSameHeader");
+        verifySuccess(headers);
+        Log.d(LOGTAG, "testRequestAddSameHeader - returning");
+    }
+
+    public void testRequestAddNullHeaders() throws Exception {
+        /**
+         * Test Request.addHeaders with a null header map. This should not generate
+         * any exceptions but accept that there are no headers to add.
+         */
+        Log.d(LOGTAG, "testRequestAddNullHeaders start ");
+        verifySuccess(null);
+        Log.d(LOGTAG, "testRequestAddNullHeaders - returning");
+    }
+
+    public void testGet() throws Exception {
+        /**
+         * Test sending a GET request. Test will pass if the events received
+         * correspond with the expected response. This should respond with the
+         * test data requested.
+         */
+        TestEventHandler testEventHandler = new TestEventHandler();
+
+        mTestWebServer.setKeepAlive(false);
+
+        Log.d(LOGTAG, "testGet start ");
+
+        // Load up expected response
+        testEventHandler.expectStatus(200);
+        testEventHandler.expectHeaders();
+        testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONNECTION], "Close");
+        testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_LENGTH], "52");
+        testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_TYPE], "text/html");
+        testEventHandler.expectData(52);
+
+        RequestHandle handle = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "GET", null, testEventHandler,
+                null, 0, false);
+
+        Log.d(LOGTAG, "testGet - sent request. Waiting");
+        handle.waitUntilComplete();
+        Log.d(LOGTAG, "testGet - sent request. Notified");
+
+        if (!testEventHandler.expectPassed()) {
+            Log.d(LOGTAG, testEventHandler.getFailureMessage());
+            fail("expectPassed was false " + testEventHandler.getFailureMessage());
+        }
+    }
+
+    public void testReuse() throws Exception {
+        /**
+         * Test sending two GET requests. Test will pass if the events
+         * received correspond with the expected response.
+         */
+        final String TEST_NAME = "testReuse";
+        Log.d(LOGTAG, TEST_NAME + " start ");
+
+        TestEventHandler testEventHandler = new TestEventHandler();
+
+        // Load up expected response
+        testEventHandler.expectStatus(200);
+        testEventHandler.expectHeaders();
+
+        TestEventHandler testEventHandler2 = new TestEventHandler();
+        testEventHandler2.expectStatus(200);
+        testEventHandler2.expectHeaders();
+
+        mTestWebServer.setAcceptLimit(2);
+
+        RequestHandle handle0 = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "GET", null, testEventHandler,
+                null, 0, false);
+        handle0.waitUntilComplete();
+        RequestHandle handle1 = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "GET", null, testEventHandler2,
+                null, 0, false);
+        handle1.waitUntilComplete();
+
+        /* It's not correct to use same listener for multiple
+           requests.  Otherwise there would be no distiction between
+           events delivered for either request. */
+
+        if (!testEventHandler.expectPassed() && !testEventHandler2.expectPassed()) {
+            Log.d(LOGTAG, testEventHandler.getFailureMessage());
+            Log.d(LOGTAG, testEventHandler2.getFailureMessage());
+            fail();
+        }
+        Log.d(LOGTAG, TEST_NAME + " - sent request. Notified");
+    }
+
+    public void testHead() throws Exception {
+        /**
+         * Test sending a HEAD request. Test will pass if the events
+         * delivered match the expected response.
+         */
+        TestEventHandler testEventHandler = new TestEventHandler();
+
+        // Load up expected response
+        testEventHandler.expectStatus(200);
+        testEventHandler.expectHeaders();
+        testEventHandler.expectNoData();
+
+        mTestWebServer.setKeepAlive(false);
+        mTestWebServer.setAcceptLimit(1);
+
+
+        Log.d(LOGTAG, "testHead start - rq = " + mRequestQueue);
+
+        RequestHandle handle = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "HEAD", null, testEventHandler,
+                null, 0, false);
+
+        Log.d(LOGTAG, "testHead - sent request waiting");
+        handle.waitUntilComplete();
+
+        if (!testEventHandler.expectPassed()) {
+            Log.d(LOGTAG, testEventHandler.getFailureMessage());
+            fail("expectPassed was false " + testEventHandler.getFailureMessage());
+        }
+    }
+
+    public void testChunked() throws Exception {
+        TestEventHandler testEventHandler = new TestEventHandler();
+
+        // Load up expected response
+        testEventHandler.expectStatus(200);
+        testEventHandler.expectHeaders();
+
+        mTestWebServer.setKeepAlive(false);
+        mTestWebServer.setChunked(true);
+        mTestWebServer.setAcceptLimit(1);
+
+
+        Log.d(LOGTAG, "testChunked start - rq = " + mRequestQueue);
+
+        RequestHandle handle = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "GET", null, testEventHandler,
+                null, 0, false);
+
+        Log.d(LOGTAG, "testChunked - sent request waiting");
+        handle.waitUntilComplete();
+
+        if (!testEventHandler.expectPassed()) {
+            Log.d(LOGTAG, testEventHandler.getFailureMessage());
+            fail("expectPassed was false " + testEventHandler.getFailureMessage());
+        }
+    }
+
+    public void verifyRedirect(int statusCode, String testName) throws Exception {
+        final String REDIRECT_TO = "http://localhost:8081/test1";
+
+        mTestWebServer.setKeepAlive(false);
+        TestWebServer redirectWebServer = new TestWebServer();
+        redirectWebServer.initServer(8081, true);
+        redirectWebServer.setKeepAlive(false);
+
+        try {
+            TestEventHandler testEventHandler = new TestEventHandler();
+            // Load up expected response
+            testEventHandler.expectStatus(statusCode);
+            testEventHandler.expectHeaders();
+            testEventHandler.expectHeaderAdd(requestHeaders[REQ_LOCATION], REDIRECT_TO);
+
+            mTestWebServer.setAcceptLimit(1);
+            mTestWebServer.setRedirect(REDIRECT_TO, statusCode);
+            redirectWebServer.setAcceptLimit(1);
+
+            Log.d(LOGTAG, testName + " start - rq = " + mRequestQueue);
+
+            RequestHandle requestHandle = mRequestQueue.queueRequest(
+                    "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false);
+            Log.d(LOGTAG, testName + " - sent request waiting");
+
+            requestHandle.waitUntilComplete();
+
+            if (!testEventHandler.expectPassed()) {
+                Log.d(LOGTAG, testEventHandler.getFailureMessage());
+                fail("expectPassed was false " + testEventHandler.getFailureMessage());
+            }
+
+            requestHandle.setupRedirect(REDIRECT_TO, statusCode, new HashMap<String, String>());
+
+            testEventHandler.expectStatus(HttpConstants.HTTP_OK);
+            testEventHandler.expectHeaders();
+            testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_LENGTH], "52");
+            testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_TYPE], "text/html");
+            // Server name should be TestWebServer+port
+            // we ignore the server tag, so don't test it
+            // testEventHandler.expectHeaderAdd(requestHeaders[REQ_SERVER], "TestWebServer8081");
+            testEventHandler.expectData(52);
+            testEventHandler.expectEndData();
+
+            requestHandle.waitUntilComplete();
+
+            if (!testEventHandler.expectPassed()) {
+                Log.d(LOGTAG, testEventHandler.getFailureMessage());
+                fail("expectPassed was false " + testEventHandler.getFailureMessage());
+             }
+        } finally {
+            Log.d(LOGTAG, testName + " - returning");
+            redirectWebServer.close();
+        }
+    }
+
+    public void testRedirect301() throws Exception {
+        verifyRedirect(HttpConstants.HTTP_MOVED_PERM, "testRedirect301");
+    }
+
+    public void testRedirect302() throws Exception {
+        verifyRedirect(HttpConstants.HTTP_MOVED_TEMP, "testRedirect302");
+    }
+
+    public void testRedirect303() throws Exception {
+        verifyRedirect(HttpConstants.HTTP_SEE_OTHER, "testRedirect303");
+    }
+
+    public void testRedirect307() throws Exception {
+        verifyRedirect(307, "testRedirect307");
+    }
+
+    public void testGetAndHead() throws Exception {
+        /**
+         * Test sending a GET and a HEAD request. Test will pass if the
+         * event received correspond with the expected response. The two
+         * requests should respond the same test data.
+         */
+        mTestWebServer.setKeepAlive(true);
+        mTestWebServer.setAcceptLimit(2);
+
+        TestEventHandler testEventHandler = new TestEventHandler();
+        testEventHandler.expectStatus(200);
+        testEventHandler.expectHeaders();
+
+        TestEventHandler leh2 = new TestEventHandler();
+        leh2.expectStatus(200);
+        leh2.expectHeaders();
+
+        RequestHandle handle0 = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false);
+        handle0.waitUntilComplete();
+        RequestHandle handle1 = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "HEAD", null, testEventHandler, null, 0, false);
+
+        Log.d(LOGTAG, "testGetAndHead - sent request. Waiting");
+        handle1.waitUntilComplete();
+
+        if (!testEventHandler.expectPassed() && !leh2.expectPassed()) {
+            Log.d(LOGTAG, testEventHandler.getFailureMessage());
+            Log.d(LOGTAG, leh2.getFailureMessage());
+            fail();
+        }
+    }
+
+    public void testPost() throws Exception {
+        /**
+         * Test sending a POST request with no body data. Test will pass if the event
+         * received correspond with the expected response. This should respond with
+         * the test data requested.
+         */
+        TestEventHandler testEventHandler = new TestEventHandler();
+
+        // Load up expected response
+        testEventHandler.expectStatus(200);
+        testEventHandler.expectHeaders();
+        testEventHandler.expectData(52);
+
+        mTestWebServer.setKeepAlive(false);
+        mTestWebServer.setAcceptLimit(1);
+
+        Log.d(LOGTAG, "testPost start - rq = " + mRequestQueue);
+
+        RequestHandle handle = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "POST", null, testEventHandler, null, 0, false);
+
+        Log.d(LOGTAG, "testPost - sent request waiting");
+        handle.waitUntilComplete();
+
+        if (!testEventHandler.expectPassed()) {
+            Log.d(LOGTAG, testEventHandler.getFailureMessage());
+            fail("expectPassed was false " + testEventHandler.getFailureMessage());
+        }
+    }
+
+
+    public void testPostWithData() throws Exception {
+        /**
+         * Test sending a POST request with body data. Test will pass if the event
+         * received correspond with the expected response. This should respond with
+         * the test data requested.
+         */
+
+        TestEventHandler testEventHandler = new TestEventHandler();
+        // Load up expected response
+        testEventHandler.expectStatus(200);
+        testEventHandler.expectHeaders();
+        testEventHandler.expectData(52);
+
+        mTestWebServer.setKeepAlive(false);
+        mTestWebServer.setAcceptLimit(1);
+
+        Log.d(LOGTAG, "testPostWithData start - rq = " + mRequestQueue);
+
+        String mBody = TestWebData.postContent;
+        int bodyLength = mBody.length();
+        if (bodyLength > 0) {
+            Log.v(LOGTAG, "testPostWithData: body " + mBody);
+        }
+        InputStream bodyProvider = new ByteArrayInputStream(mBody.getBytes());
+
+        RequestHandle handle = mRequestQueue.queueRequest(
+                "http://localhost:8080/test1", "POST", null, testEventHandler, bodyProvider, bodyLength, false);
+
+        Log.d(LOGTAG, "testPostWithData - sent request waiting");
+        handle.waitUntilComplete();
+
+        if (!testEventHandler.expectPassed()) {
+            Log.d(LOGTAG, testEventHandler.getFailureMessage());
+            fail("expectPassed was false " + testEventHandler.getFailureMessage());
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java b/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java
new file mode 100644
index 0000000..eec82aa
--- /dev/null
+++ b/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Minimal test for JDBC driver
+ */
+public class SQLiteJDBCDriverTest extends AbstractJDBCDriverTest {
+
+    private File dbFile;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        dbFile = File.createTempFile("sqliteTestDB", null);
+    }
+    
+    @Override
+    protected void tearDown() throws Exception {
+        if(dbFile != null) {
+            dbFile.delete();
+        }
+        super.tearDown();
+    }
+
+    @Override
+    protected String getConnectionURL() {
+        return "jdbc:sqlite:/" + dbFile;
+    }
+
+    @Override
+    protected File getDbFile() {
+        return dbFile;
+    }
+
+    @Override
+    protected String getJDBCDriverClassName() {
+        return "SQLite.JDBCDriver";
+    }
+    
+    // Regression test for (Noser) #255: PreparedStatement.executeUpdate results
+    // in VM crashing with SIGABRT.
+    @MediumTest
+    public void test_connection3() throws Exception {
+        PreparedStatement prst = null;
+        Statement st = null;
+        Connection conn = null;
+        try {
+            Class.forName("SQLite.JDBCDriver").newInstance();
+            if (dbFile.exists()) {
+                dbFile.delete();
+            }
+            conn = DriverManager.getConnection("jdbc:sqlite:/"
+                        + dbFile.getPath());
+            assertNotNull(conn);
+
+            // create table
+            st = conn.createStatement();
+            String sql = "CREATE TABLE zoo (ZID INTEGER NOT NULL, family VARCHAR (20) NOT NULL, name VARCHAR (20) NOT NULL, PRIMARY KEY(ZID) )";
+            st.executeUpdate(sql);
+            
+            String update = "update zoo set family = ? where name = ?;";
+            prst = conn.prepareStatement(update);
+            prst.setString(1, "cat");
+            prst.setString(2, "Yasha");
+            // st = conn.createStatement();
+            // st.execute("select * from zoo where family = 'cat'");
+            // ResultSet rs = st.getResultSet();
+            // assertEquals(0, getCount(rs));
+            prst.executeUpdate();
+            // st.execute("select * from zoo where family = 'cat'");
+            // ResultSet rs1 = st.getResultSet();
+            // assertEquals(1, getCount(rs1));
+            try {
+                prst = conn.prepareStatement("");
+                prst.execute();
+                fail("SQLException is not thrown");
+            } catch (SQLException e) {
+                // expected
+            }
+            
+            try {
+                conn.prepareStatement(null);
+                fail("NPE is not thrown");
+            } catch (Exception e) {
+                // expected
+            }
+            try {
+                st = conn.createStatement();
+                st.execute("drop table if exists zoo");
+                
+            } catch (SQLException e) {
+                fail("Couldn't drop table: " + e.getMessage());
+            } finally {
+                try {
+                    st.close();
+                    conn.close();
+                } catch (SQLException ee) {
+                }
+            }
+        } finally {
+            try {
+                if (prst != null) {
+                    prst.close();
+                }
+                if (st != null) {
+                    st.close();
+                }
+            } catch (SQLException ee) {
+            }
+        }
+
+    }
+    
+}
diff --git a/tests/CoreTests/android/core/SSLPerformanceTest.java b/tests/CoreTests/android/core/SSLPerformanceTest.java
new file mode 100644
index 0000000..e2bd9c5
--- /dev/null
+++ b/tests/CoreTests/android/core/SSLPerformanceTest.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2009 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.core;
+
+import android.test.AndroidTestCase;
+import android.os.Debug;
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.conn.SingleClientConnManager;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.HttpResponse;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.security.cert.Certificate;
+import java.security.Principal;
+import java.security.KeyManagementException;
+import java.util.Arrays;
+
+public class SSLPerformanceTest extends AndroidTestCase {
+
+    static final byte[] SESSION_DATA = new byte[6000];
+    static {
+        for (int i = 0; i < SESSION_DATA.length; i++) {
+            SESSION_DATA[i] = (byte) i;
+        }
+    }
+
+    static final File dataDir = new File("/data/data/android.core/");
+    static final File filesDir = new File(dataDir, "files");
+    static final File dbDir = new File(dataDir, "databases");
+
+    static final String CACHE_DIR
+            = SSLPerformanceTest.class.getName() + "/cache";
+
+    static final int ITERATIONS = 10;
+
+    public void testCreateNewEmptyDatabase() {
+        deleteDatabase();
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+        cache.getSessionData("crazybob.org", 443);
+
+        stopwatch.stop();
+    }
+
+    public void testCreateNewEmptyDirectory() throws IOException {
+        deleteDirectory();
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+                getCacheDirectory());
+        cache.getSessionData("crazybob.org", 443);
+
+        stopwatch.stop();
+    }
+
+    public void testOpenDatabaseWith10Sessions() {
+        deleteDatabase();
+
+        DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+        putSessionsIn(cache);
+        closeDatabase();
+
+        System.err.println("Size of ssl_sessions.db w/ 10 sessions: "
+                + new File(dbDir, "ssl_sessions.db").length());
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        cache = new DatabaseSessionCache(getContext());
+        cache.getSessionData("crazybob.org", 443);
+
+        stopwatch.stop();
+    }
+
+    public void testOpenDirectoryWith10Sessions() throws IOException {
+        deleteDirectory();
+
+        SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+                getCacheDirectory());
+        putSessionsIn(cache);
+        closeDirectoryCache();
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        cache = FileClientSessionCache.usingDirectory(
+                getCacheDirectory());
+        cache.getSessionData("crazybob.org", 443);
+
+        stopwatch.stop();
+    }
+
+    public void testGetSessionFromDatabase() {
+        deleteDatabase();
+
+        DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+        cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+        closeDatabase();
+
+        cache = new DatabaseSessionCache(getContext());
+        cache.getSessionData("crazybob.org", 443);
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        byte[] sessionData = cache.getSessionData("foo", 443);
+
+        stopwatch.stop();
+
+        assertTrue(Arrays.equals(SESSION_DATA, sessionData));
+    }
+
+    public void testGetSessionFromDirectory() throws IOException {
+        deleteDirectory();
+
+        SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+                getCacheDirectory());
+        cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+        closeDirectoryCache();
+
+        cache = FileClientSessionCache.usingDirectory(
+                getCacheDirectory());
+        cache.getSessionData("crazybob.org", 443);
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        byte[] sessionData = cache.getSessionData("foo", 443);
+
+        stopwatch.stop();
+        
+        assertTrue(Arrays.equals(SESSION_DATA, sessionData));
+    }
+
+    public void testPutSessionIntoDatabase() {
+        deleteDatabase();
+
+        DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+        cache.getSessionData("crazybob.org", 443);
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+
+        stopwatch.stop();
+    }
+
+    public void testPutSessionIntoDirectory() throws IOException {
+        deleteDirectory();
+
+        SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+                getCacheDirectory());
+        cache.getSessionData("crazybob.org", 443);
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+
+        stopwatch.stop();
+    }
+
+    public void testEngineInit() throws IOException, KeyManagementException {
+        Stopwatch stopwatch = new Stopwatch();
+
+        new SSLContextImpl().engineInit(null, null, null);
+
+        stopwatch.stop();
+    }
+
+    public void testWebRequestWithoutCache() throws IOException,
+            KeyManagementException {
+        SSLContextImpl sslContext = new SSLContextImpl();
+        sslContext.engineInit(null, null, null);
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        getVerisignDotCom(sslContext);
+
+        stopwatch.stop();
+    }
+
+    public void testWebRequestWithFileCache() throws IOException,
+            KeyManagementException {
+        deleteDirectory();
+
+        SSLContextImpl sslContext = new SSLContextImpl();
+        sslContext.engineInit(null, null, null,
+                FileClientSessionCache.usingDirectory(getCacheDirectory()),
+                null);
+
+        // Make sure www.google.com is in the cache.
+        getVerisignDotCom(sslContext);
+
+        // Re-initialize so we hit the file cache.
+        sslContext.engineInit(null, null, null,
+                FileClientSessionCache.usingDirectory(getCacheDirectory()),
+                null);
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        getVerisignDotCom(sslContext);
+
+        stopwatch.stop();
+    }
+
+    public void testWebRequestWithInMemoryCache() throws IOException,
+            KeyManagementException {
+        deleteDirectory();
+
+        SSLContextImpl sslContext = new SSLContextImpl();
+        sslContext.engineInit(null, null, null);
+
+        // Make sure www.google.com is in the cache.
+        getVerisignDotCom(sslContext);
+
+        Stopwatch stopwatch = new Stopwatch();
+
+        getVerisignDotCom(sslContext);
+
+        stopwatch.stop();
+    }
+
+    private void getVerisignDotCom(SSLContextImpl sslContext)
+            throws IOException {
+        SchemeRegistry schemeRegistry = new SchemeRegistry();
+        schemeRegistry.register(new Scheme("https",
+                new SSLSocketFactory(sslContext.engineGetSocketFactory()),
+                443));
+
+        ClientConnectionManager manager =
+                new SingleClientConnManager(null, schemeRegistry);
+
+        new DefaultHttpClient(manager, null).execute(
+                new HttpGet("https://www.verisign.com"),
+                new ResponseHandler<Object>() {
+                    public Object handleResponse(HttpResponse response)
+                            throws ClientProtocolException, IOException {
+                        return null;
+                    }
+                });
+    }
+
+    private void putSessionsIn(SSLClientSessionCache cache) {
+        for (int i = 0; i < 10; i++) {
+            cache.putSessionData(new FakeSession("host" + i), SESSION_DATA);
+        }
+    }
+
+    private void deleteDatabase() {
+        closeDatabase();
+        if (!new File(dbDir, "ssl_sessions.db").delete()) {
+            System.err.println("Failed to delete database.");
+        }
+    }
+
+    private void closeDatabase() {
+        if (DatabaseSessionCache.sDefaultDatabaseHelper != null) {
+            DatabaseSessionCache.sDefaultDatabaseHelper.close();
+        }
+        DatabaseSessionCache.sDefaultDatabaseHelper = null;
+        DatabaseSessionCache.sHookInitializationDone = false;
+        DatabaseSessionCache.mNeedsCacheLoad = true;
+    }
+
+    private void deleteDirectory() {
+        closeDirectoryCache();
+
+        File dir = getCacheDirectory();
+        if (!dir.exists()) {
+            return;
+        }
+        for (File file : dir.listFiles()) {
+            file.delete();
+        }
+        if (!dir.delete()) {
+            System.err.println("Failed to delete directory.");
+        }
+    }
+
+    private void closeDirectoryCache() {
+        try {
+            Method reset = FileClientSessionCache.class
+                    .getDeclaredMethod("reset");
+            reset.setAccessible(true);
+            reset.invoke(null);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(e);
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private File getCacheDirectory() {
+        return new File(getContext().getFilesDir(), CACHE_DIR);
+    }
+
+    class Stopwatch {
+        {
+            Debug.startAllocCounting();
+        }
+        long start = System.nanoTime();
+
+        void stop() {
+            long elapsed = (System.nanoTime() - start) / 1000;
+            Debug.stopAllocCounting();
+            System.err.println(getName() + ": " + elapsed + "us, "
+                + Debug.getThreadAllocCount() + " allocations, "
+                + Debug.getThreadAllocSize() + " bytes");
+        }
+    }
+}
+
+class FakeSession implements SSLSession {
+    final String host;
+
+    FakeSession(String host) {
+        this.host = host;
+    }
+
+    public int getApplicationBufferSize() {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getCipherSuite() {
+        throw new UnsupportedOperationException();
+    }
+
+    public long getCreationTime() {
+        throw new UnsupportedOperationException();
+    }
+
+    public byte[] getId() {
+        return host.getBytes();
+    }
+
+    public long getLastAccessedTime() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Certificate[] getLocalCertificates() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Principal getLocalPrincipal() {
+        throw new UnsupportedOperationException();
+    }
+
+    public int getPacketBufferSize() {
+        throw new UnsupportedOperationException();
+    }
+
+    public javax.security.cert.X509Certificate[] getPeerCertificateChain() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Certificate[] getPeerCertificates() {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getPeerHost() {
+        return host;
+    }
+
+    public int getPeerPort() {
+        return 443;
+    }
+
+    public Principal getPeerPrincipal() {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getProtocol() {
+        throw new UnsupportedOperationException();
+    }
+
+    public SSLSessionContext getSessionContext() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object getValue(String name) {
+        throw new UnsupportedOperationException();
+    }
+
+    public String[] getValueNames() {
+        throw new UnsupportedOperationException();
+    }
+
+    public void invalidate() {
+        throw new UnsupportedOperationException();
+    }
+
+    public boolean isValid() {
+        throw new UnsupportedOperationException();
+    }
+
+    public void putValue(String name, Object value) {
+        throw new UnsupportedOperationException();
+    }
+
+    public void removeValue(String name) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/tests/CoreTests/android/core/SSLSocketTest.java b/tests/CoreTests/android/core/SSLSocketTest.java
new file mode 100644
index 0000000..088fa8c
--- /dev/null
+++ b/tests/CoreTests/android/core/SSLSocketTest.java
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.KeyManagementException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * SSL integration tests that hit real servers.
+ */
+public class SSLSocketTest extends TestCase {
+
+    private static SSLSocketFactory clientFactory =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+    /**
+     * Does a number of HTTPS requests on some host and consumes the response.
+     * We don't use the HttpsUrlConnection class, but do this on our own
+     * with the SSLSocket class. This gives us a chance to test the basic
+     * behavior of SSL.
+     *
+     * @param host      The host name the request is being sent to.
+     * @param port      The port the request is being sent to.
+     * @param path      The path being requested (e.g. "/index.html").
+     * @param outerLoop The number of times we reconnect and do the request.
+     * @param innerLoop The number of times we do the request for each
+     *                  connection (using HTTP keep-alive).
+     * @param delay     The delay after each request (in seconds).
+     * @throws IOException When a problem occurs.
+     */
+    private void fetch(SSLSocketFactory socketFactory, String host, int port,
+            boolean secure, String path, int outerLoop, int innerLoop,
+            int delay, int timeout) throws IOException {
+        InetSocketAddress address = new InetSocketAddress(host, port);
+
+        for (int i = 0; i < outerLoop; i++) {
+            // Connect to the remote host
+            Socket socket = secure ? socketFactory.createSocket()
+                    : new Socket();
+            if (timeout >= 0) {
+                socket.setKeepAlive(true);
+                socket.setSoTimeout(timeout * 1000);
+            }
+            socket.connect(address);
+
+            // Get the streams
+            OutputStream output = socket.getOutputStream();
+            PrintWriter writer = new PrintWriter(output);
+
+            try {
+                DataInputStream input = new DataInputStream(socket.getInputStream());
+                try {
+                    for (int j = 0; j < innerLoop; j++) {
+                        android.util.Log.d("SSLSocketTest",
+                                "GET https://" + host + path + " HTTP/1.1");
+
+                        // Send a request
+                        writer.println("GET https://" + host + path + " HTTP/1.1\r");
+                        writer.println("Host: " + host + "\r");
+                        writer.println("Connection: " +
+                                (j == innerLoop - 1 ? "Close" : "Keep-Alive")
+                                + "\r");
+                        writer.println("\r");
+                        writer.flush();
+
+                        int length = -1;
+                        boolean chunked = false;
+
+                        String line = input.readLine();
+
+                        if (line == null) {
+                            throw new IOException("No response from server");
+                            // android.util.Log.d("SSLSocketTest", "No response from server");
+                        }
+
+                        // Consume the headers, check content length and encoding type
+                        while (line != null && line.length() != 0) {
+//                    System.out.println(line);
+                            int dot = line.indexOf(':');
+                            if (dot != -1) {
+                                String key = line.substring(0, dot).trim();
+                                String value = line.substring(dot + 1).trim();
+
+                                if ("Content-Length".equalsIgnoreCase(key)) {
+                                    length = Integer.valueOf(value);
+                                } else if ("Transfer-Encoding".equalsIgnoreCase(key)) {
+                                    chunked = "Chunked".equalsIgnoreCase(value);
+                                }
+
+                            }
+                            line = input.readLine();
+                        }
+
+                        assertTrue("Need either content length or chunked encoding", length != -1
+                                || chunked);
+
+                        // Consume the content itself
+                        if (chunked) {
+                            length = Integer.parseInt(input.readLine(), 16);
+                            while (length != 0) {
+                                byte[] buffer = new byte[length];
+                                input.readFully(buffer);
+                                input.readLine();
+                                length = Integer.parseInt(input.readLine(), 16);
+                            }
+                            input.readLine();
+                        } else {
+                            byte[] buffer = new byte[length];
+                            input.readFully(buffer);
+                        }
+
+                        // Sleep for the given number of seconds
+                        try {
+                            Thread.sleep(delay * 1000);
+                        } catch (InterruptedException ex) {
+                            // Shut up!
+                        }
+                    }
+                } finally {
+                    input.close();
+                }
+            } finally {
+                writer.close();
+            }
+            // Close the connection
+            socket.close();
+        }
+    }
+
+    /**
+     * Invokes fetch() with the default socket factory.
+     */
+    private void fetch(String host, int port, boolean secure, String path,
+            int outerLoop, int innerLoop,
+            int delay, int timeout) throws IOException {
+        fetch(clientFactory, host, port, secure, path, outerLoop, innerLoop,
+                delay, timeout);
+    }
+
+    /**
+     * Does a single request for each of the hosts. Consumes the response.
+     *
+     * @throws IOException If a problem occurs.
+     */
+    public void testSimple() throws IOException {
+        fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 1, 0, 60);
+        fetch("mail.google.com", 443, true, "/mail/", 1, 1, 0, 60);
+        fetch("www.paypal.com", 443, true, "/", 1, 1, 0, 60);
+        fetch("www.yellownet.ch", 443, true, "/", 1, 1, 0, 60);
+    }
+
+    /**
+     * Does repeated requests for each of the hosts, with the connection being
+     * closed in between.
+     *
+     * @throws IOException If a problem occurs.
+     */
+    public void testRepeatedClose() throws IOException {
+        fetch("www.fortify.net", 443, true, "/sslcheck.html", 10, 1, 0, 60);
+        fetch("mail.google.com", 443, true, "/mail/", 10, 1, 0, 60);
+        fetch("www.paypal.com", 443, true, "/", 10, 1, 0, 60);
+        fetch("www.yellownet.ch", 443, true, "/", 10, 1, 0, 60);
+    }
+
+    /**
+     * Does repeated requests for each of the hosts, with the connection being
+     * kept alive in between.
+     *
+     * @throws IOException If a problem occurs.
+     */
+    public void testRepeatedKeepAlive() throws IOException {
+        fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 10, 0, 60);
+        fetch("mail.google.com", 443, true, "/mail/", 1, 10, 0, 60);
+
+        // These two don't accept keep-alive
+        // fetch("www.paypal.com", 443, "/", 1, 10);
+        // fetch("www.yellownet.ch", 443, "/", 1, 10);
+    }
+
+    /**
+     * Does repeated requests for each of the hosts, with the connection being
+     * closed in between. Waits a couple of seconds after each request, but
+     * stays within a reasonable timeout. Expectation is that the connection
+     * stays open.
+     *
+     * @throws IOException If a problem occurs.
+     */
+    public void testShortTimeout() throws IOException {
+        fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 10, 5, 60);
+        fetch("mail.google.com", 443, true, "/mail/", 1, 10, 5, 60);
+
+        // These two don't accept keep-alive
+        // fetch("www.paypal.com", 443, "/", 1, 10);
+        // fetch("www.yellownet.ch", 443, "/", 1, 10);
+    }
+
+    /**
+     * Does repeated requests for each of the hosts, with the connection being
+     * kept alive in between. Waits a longer time after each request.
+     * Expectation is that the host closes the connection.
+     */
+    public void testLongTimeout() {
+        // Seems to have a veeeery long timeout.
+        // fetch("www.fortify.net", 443, "/sslcheck.html", 1, 2, 60);
+
+        // Google has a 60s timeout, so 90s of waiting should trigger it.
+        try {
+            fetch("mail.google.com", 443, true, "/mail/", 1, 2, 90, 180);
+            fail("Oops - timeout expected.");
+        } catch (IOException ex) {
+            // Expected.
+        }
+
+        // These two don't accept keep-alive
+        // fetch("www.paypal.com", 443, "/", 1, 10);
+        // fetch("www.yellownet.ch", 443, "/", 1, 10);
+    }
+
+    /**
+     * Does repeated requests for each of the hosts, with the connection being
+     * closed in between. Waits a longer time after each request. Expectation is
+     * that the host closes the connection.
+     */
+    // These two need manual interaction to reproduce...
+    public void xxtestBrokenConnection() {
+        try {
+            fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 2, 60, 60);
+            fail("Oops - timeout expected.");
+        } catch (IOException ex) {
+            android.util.Log.d("SSLSocketTest", "Exception", ex);
+            // Expected.
+        }
+
+        // These two don't accept keep-alive
+        // fetch("www.paypal.com", 443, "/", 1, 10);
+        // fetch("www.yellownet.ch", 443, "/", 1, 10);
+    }
+
+    /**
+     * Does repeated requests for each of the hosts, with the connection being
+     * closed in between. Waits a longer time after each request. Expectation is
+     * that the host closes the connection.
+     */
+    // These two need manual interaction to reproduce...
+    public void xxtestBrokenConnection2() {
+        try {
+            fetch("www.heise.de", 80, false, "/index.html", 1, 2, 60, 60);
+            fail("Oops - timeout expected.");
+        } catch (IOException ex) {
+            android.util.Log.d("SSLSocketTest", "Exception", ex);
+            // Expected.
+        }
+
+        // These two don't accept keep-alive
+        // fetch("www.paypal.com", 443, "/", 1, 10);
+        // fetch("www.yellownet.ch", 443, "/", 1, 10);
+    }
+
+    /**
+     * Regression test for 865926: SSLContext.init() should
+     * use default values for null arguments.
+     */
+    public void testContextInitNullArgs() throws Exception {
+            SSLContext ctx = SSLContext.getInstance("TLS");
+            ctx.init(null, null, null);
+    }
+
+    /**
+     * Regression test for 963650: javax.net.ssl.KeyManager has no implemented
+     * (documented?) algorithms.
+     */
+    public void testDefaultAlgorithms() throws Exception {
+            SSLContext ctx = SSLContext.getInstance("TLS");
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
+            KeyStore ks = KeyStore.getInstance("BKS");
+
+            assertEquals("X509", kmf.getAlgorithm());
+            assertEquals("X509", KeyManagerFactory.getDefaultAlgorithm());
+
+            assertEquals("BKS", ks.getType());
+            assertEquals("BKS", KeyStore.getDefaultType());
+    }
+
+    /**
+     * Regression test for problem where close() resulted in a hand if
+     * a different thread was sitting in a blocking read or write.
+     */
+    public void testMultithreadedClose() throws Exception {
+            InetSocketAddress address = new InetSocketAddress("www.fortify.net", 443);
+            final Socket socket = clientFactory.createSocket();
+            socket.connect(address);
+
+            Thread reader = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        byte[] buffer = new byte[512];
+                        InputStream stream = socket.getInputStream();
+                        socket.getInputStream().read(buffer);
+                    } catch (Exception ex) {
+                        android.util.Log.d("SSLSocketTest",
+                                "testMultithreadedClose() reader got " + ex.toString());
+                    }
+                }
+            };
+
+            Thread closer = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        Thread.sleep(5000);
+                        socket.close();
+                    } catch (Exception ex) {
+                        android.util.Log.d("SSLSocketTest",
+                                "testMultithreadedClose() closer got " + ex.toString());
+                    }
+                }
+            };
+
+            android.util.Log.d("SSLSocketTest", "testMultithreadedClose() starting reader...");
+            reader.start();
+            android.util.Log.d("SSLSocketTest", "testMultithreadedClose() starting closer...");
+            closer.start();
+
+            long t1 = System.currentTimeMillis();
+            android.util.Log.d("SSLSocketTest", "testMultithreadedClose() joining reader...");
+            reader.join(30000);
+            android.util.Log.d("SSLSocketTest", "testMultithreadedClose() joining closer...");
+            closer.join(30000);
+            long t2 = System.currentTimeMillis();
+
+            assertTrue("Concurrent close() hangs", t2 - t1 < 30000);
+    }
+
+    private int multithreadedFetchRuns;
+
+    private int multithreadedFetchWins;
+
+    private Random multithreadedFetchRandom = new Random();
+
+    /**
+     * Regression test for problem where multiple threads with multiple SSL
+     * connection would cause problems due to either missing native locking
+     * or the slowness of the SSL connections.
+     */
+    public void testMultithreadedFetch() {
+        Thread[] threads = new Thread[10];
+
+        for (int i = 0; i < threads.length; i++) {
+            threads[i] = new Thread() {
+                @Override
+                public void run() {
+                    for (int i = 0; i < 10; i++) {
+                        try {
+                            multithreadedFetchRuns++;
+                            switch (multithreadedFetchRandom.nextInt(4)) {
+                                case 0: {
+                                    fetch("www.fortify.net", 443,
+                                            true, "/sslcheck.html", 1, 1, 0, 60);
+                                    break;
+                                }
+
+                                case 1: {
+                                    fetch("mail.google.com", 443, true, "/mail/", 1, 1, 0, 60);
+                                    break;
+                                }
+
+                                case 2: {
+                                    fetch("www.paypal.com", 443, true, "/", 1, 1, 0, 60);
+                                    break;
+                                }
+
+                                case 3: {
+                                    fetch("www.yellownet.ch", 443, true, "/", 1, 1, 0, 60);
+                                    break;
+                                }
+                            }
+                            multithreadedFetchWins++;
+                        } catch (Exception ex) {
+                            android.util.Log.d("SSLSocketTest",
+                                    "testMultithreadedFetch() got Exception", ex);
+                        }
+                    }
+                }
+            };
+            threads[i].start();
+
+            android.util.Log.d("SSLSocketTest", "testMultithreadedFetch() started thread #" + i);
+        }
+
+        for (int i = 0; i < threads.length; i++) {
+            try {
+                threads[i].join();
+                android.util.Log.d("SSLSocketTest", "testMultithreadedFetch() joined thread #" + i);
+            } catch (InterruptedException ex) {
+                // Not interested.
+            }
+        }
+
+        assertTrue("At least 95% of multithreaded SSL connections must succeed",
+                multithreadedFetchWins >= (multithreadedFetchRuns * 95) / 100);
+    }
+
+    // -------------------------------------------------------------------------
+    // Regression test for #1204316: Missing client cert unit test. Passes on
+    // both Android and the RI. To use on the RI, install Apache Commons and
+    // replace the references to the base64-encoded keys by the JKS versions.
+    // -------------------------------------------------------------------------
+    
+    /** 
+     * Defines the keystore contents for the server, JKS version. Holds just a
+     * single self-generated key. The subject name is "Test Server".
+     */
+    private static final String SERVER_KEYS_JKS = 
+        "/u3+7QAAAAIAAAABAAAAAQAFbXlrZXkAAAEaWFfBeAAAArowggK2MA4GCisGAQQBKgIRAQEFAASC" +
+        "AqI2kp5XjnF8YZkhcF92YsJNQkvsmH7zqMM87j23zSoV4DwyE3XeC/gZWq1ToScIhoqZkzlbWcu4" +
+        "T/Zfc/DrfGk/rKbBL1uWKGZ8fMtlZk8KoAhxZk1JSyJvdkyKxqmzUbxk1OFMlN2VJNu97FPVH+du" +
+        "dvjTvmpdoM81INWBW/1fZJeQeDvn4mMbbe0IxgpiLnI9WSevlaDP/sm1X3iO9yEyzHLL+M5Erspo" +
+        "Cwa558fOu5DdsICMXhvDQxjWFKFhPHnKtGe+VvwkG9/bAaDgx3kfhk0w5zvdnkKb+8Ed9ylNRzdk" +
+        "ocAa/mxlMTOsTvDKXjjsBupNPIIj7OP4GNnZaxkJjSs98pEO67op1GX2qhy6FSOPNuq8k/65HzUc" +
+        "PYn6voEeh6vm02U/sjEnzRevQ2+2wXoAdp0EwtQ/DlMe+NvcwPGWKuMgX4A4L93DZGb04N2VmAU3" +
+        "YLOtZwTO0LbuWrcCM/q99G/7LcczkxIVrO2I/rh8RXVczlf9QzcrFObFv4ATuspWJ8xG7DhsMbnk" +
+        "rT94Pq6TogYeoz8o8ZMykesAqN6mt/9+ToIemmXv+e+KU1hI5oLwWMnUG6dXM6hIvrULY6o+QCPH" +
+        "172YQJMa+68HAeS+itBTAF4Clm/bLn6reHCGGU6vNdwU0lYldpiOj9cB3t+u2UuLo6tiFWjLf5Zs" +
+        "EQJETd4g/EK9nHxJn0GAKrWnTw7pEHQJ08elzUuy04C/jEEG+4QXU1InzS4o/kR0Sqz2WTGDoSoq" +
+        "ewuPRU5bzQs/b9daq3mXrnPtRBL6HfSDAdpTK76iHqLCGdqx3avHjVSBm4zFvEuYBCev+3iKOBmg" +
+        "yh7eQRTjz4UOWfy85omMBr7lK8PtfVBDzOXpasxS0uBgdUyBDX4tO6k9jZ8a1kmQRQAAAAEABVgu" +
+        "NTA5AAACSDCCAkQwggGtAgRIR8SKMA0GCSqGSIb3DQEBBAUAMGkxCzAJBgNVBAYTAlVTMRMwEQYD" +
+        "VQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQHEwNNVFYxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMH" +
+        "QW5kcm9pZDEUMBIGA1UEAxMLVGVzdCBTZXJ2ZXIwHhcNMDgwNjA1MTA0ODQyWhcNMDgwOTAzMTA0" +
+        "ODQyWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8w" +
+        "DQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMIGf" +
+        "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwoC6chqCI84rj1PrXuJgbiit4EV909zR6N0jNlYfg" +
+        "itwB39bP39wH03rFm8T59b3mbSptnGmCIpLZn25KPPFsYD3JJ+wFlmiUdEP9H05flfwtFQJnw9uT" +
+        "3rRIdYVMPcQ3RoZzwAMliGr882I2thIDbA6xjGU/1nRIdvk0LtxH3QIDAQABMA0GCSqGSIb3DQEB" +
+        "BAUAA4GBAJn+6YgUlY18Ie+0+Vt8oEi81DNi/bfPrAUAh63fhhBikx/3R9dl3wh09Z6p7cIdNxjW" +
+        "n2ll+cRW9eqF7z75F0Omm0C7/KAEPjukVbszmzeU5VqzkpSt0j84YWi+TfcHRrfvhLbrlmGITVpY" +
+        "ol5pHLDyqGmDs53pgwipWqsn/nEXEBgj3EoqPeqHbDf7YaP8h/5BSt0=";
+
+    /** 
+     * Defines the keystore contents for the server, BKS version. Holds just a
+     * single self-generated key. The subject name is "Test Server".
+     */
+    private static final String SERVER_KEYS_BKS = 
+        "AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41" +
+        "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" +
+        "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" +
+        "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw" +
+        "MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" +
+        "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl" +
+        "cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy" +
+        "DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV" +
+        "zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG" +
+        "9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU" +
+        "hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV" +
+        "yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx" +
+        "4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR" +
+        "MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN" +
+        "vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs" +
+        "P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck" +
+        "MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM" +
+        "J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI" +
+        "rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f" +
+        "V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx" +
+        "OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt" +
+        "bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw" +
+        "1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" +
+        "k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw=";
+    
+    /** 
+     * Defines the keystore contents for the client, JKS version. Holds just a
+     * single self-generated key. The subject name is "Test Client".
+     */
+    private static final String CLIENT_KEYS_JKS = 
+        "/u3+7QAAAAIAAAABAAAAAQAFbXlrZXkAAAEaWFhyMAAAArkwggK1MA4GCisGAQQBKgIRAQEFAASC" +
+        "AqGVSfXolBStZy4nnRNn4fAr+S7kfU2BS23wwW8uB2Ru3GvtLzlK9q08Gvq/LNqBafjyFTVL5FV5" +
+        "SED/8YomO5a98GpskSeRvytCiTBLJdgGhws5TOGekgIAcBROPGIyOtJPQ0HfOQs+BqgzGDHzHQhw" +
+        "u/8Tm6yQwiP+W/1I9B1QnaEztZA3mhTyMMJsmsFTYroGgAog885D5Cmzd8sYGfxec3R6I+xcmBAY" +
+        "eibR5kGpWwt1R+qMvRrtBqh5r6WSKhCBNax+SJVbtUNRiKyjKccdJg6fGqIWWeivwYTy0OhjA6b4" +
+        "NiZ/ZZs5pxFGWUj/Rlp0RYy8fCF6aw5/5s4Bf4MI6dPSqMG8Hf7sJR91GbcELyzPdM0h5lNavgit" +
+        "QPEzKeuDrGxhY1frJThBsNsS0gxeu+OgfJPEb/H4lpYX5IvuIGbWKcxoO9zq4/fimIZkdA8A+3eY" +
+        "mfDaowvy65NBVQPJSxaOyFhLHfeLqOeCsVENAea02vA7andZHTZehvcrqyKtm+z8ncHGRC2H9H8O" +
+        "jKwKHfxxrYY/jMAKLl00+PBb3kspO+BHI2EcQnQuMw/zr83OR9Meq4TJ0TMuNkApZELAeFckIBbS" +
+        "rBr8NNjAIfjuCTuKHhsTFWiHfk9ZIzigxXagfeDRiyVc6khOuF/bGorj23N2o7Rf3uLoU6PyXWi4" +
+        "uhctR1aL6NzxDoK2PbYCeA9hxbDv8emaVPIzlVwpPK3Ruvv9mkjcOhZ74J8bPK2fQmbplbOljcZi" +
+        "tZijOfzcO/11JrwhuJZRA6wanTqHoujgChV9EukVrmbWGGAcewFnAsSbFXIik7/+QznXaDIt5NgL" +
+        "H/Bcz4Z/fdV7Ae1eUaxKXdPbI//4J+8liVT/d8awjW2tldIaDlmGMR3aoc830+3mAAAAAQAFWC41" +
+        "MDkAAAJIMIICRDCCAa0CBEhHxLgwDQYJKoZIhvcNAQEEBQAwaTELMAkGA1UEBhMCVVMxEzARBgNV" +
+        "BAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01UVjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdB" +
+        "bmRyb2lkMRQwEgYDVQQDEwtUZXN0IENsaWVudDAeFw0wODA2MDUxMDQ5MjhaFw0wODA5MDMxMDQ5" +
+        "MjhaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQHEwNNVFYxDzAN" +
+        "BgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEUMBIGA1UEAxMLVGVzdCBDbGllbnQwgZ8w" +
+        "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIK3Q+KiFbmCGg422TAo4gggdhMH6FJhiuz8DxRyeMKR" +
+        "UAfP4MK0wtc8N42waZ6OKvxpBFUy0BRfBsX0GD4Ku99yu9/tavSigTraeJtwV3WWRRjIqk7L3wX5" +
+        "cmgS2KSD43Y0rNUKrko26lnt9N4qiYRBSj+tcAN3Lx9+ptqk1LApAgMBAAEwDQYJKoZIhvcNAQEE" +
+        "BQADgYEANb7Q1GVSuy1RPJ0FmiXoMYCCtvlRLkmJphwxovK0cAQK12Vll+yAzBhHiQHy/RA11mng" +
+        "wYudC7u3P8X/tBT8GR1Yk7QW3KgFyPafp3lQBBCraSsfrjKj+dCLig1uBLUr4f68W8VFWZWWTHqp" +
+        "NMGpCX6qmjbkJQLVK/Yfo1ePaUexPSOX0G9m8+DoV3iyNw6at01NRw==";
+
+    /** 
+     * Defines the keystore contents for the client, BKS version. Holds just a
+     * single self-generated key. The subject name is "Test Client".
+     */
+    private static final String CLIENT_KEYS_BKS = 
+        "AAAAAQAAABT4Rka6fxbFps98Y5k2VilmbibNkQAABfQEAAVteWtleQAAARpYl+POAAAAAQAFWC41" +
+        "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU9TANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" +
+        "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" +
+        "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgQ2xpZW50MB4XDTA4MDYwNTExNTg0NVoXDTA4MDkw" +
+        "MzExNTg0NVowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" +
+        "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IENsaWVu" +
+        "dDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApUvmWsQDHPpbDKK13Yez2/q54tTOmRml/qva" +
+        "2K6dZjkjSTW0iRuk7ztaVEvdJpfVIDv1oBsCI51ttyLHROy1epjF+GoL74mJb7fkcd0VOoSOTjtD" +
+        "+3GgZkHPAm5YmUYxiJXqxKKJJqMCTIW46eJaA2nAep9QIwZ14/NFAs4ObV8CAwEAATANBgkqhkiG" +
+        "9w0BAQUFAAOBgQCJrCr3hZQFDlLIfsSKI1/w+BLvyf4fubOid0pBxfklR8KBNPTiqjSmu7pd/C/F" +
+        "1FR8CdZUDoPflZHCOU+fj5r5KUC1HyigY/tEUvlforBpfB0uCF+tXW4DbUfOWhfMtLV4nCOJOOZg" +
+        "awfZLJWBJouLKOp427vDftxTSB+Ks8YjlgAAAqwAAAAU+NH6TtrzjyDdCXm5B6Vo7xX5G4YAAAZx" +
+        "EAUkcZtmykn7YdaYxC1jRFJ+GEJpC8nZVg83QClVuCSIS8a5f8Hl44Bk4oepOZsPzhtz3RdVzDVi" +
+        "RFfoyZFsrk9F5bDTVJ6sQbb/1nfJkLhZFXokka0vND5AXMSoD5Bj1Fqem3cK7fSUyqKvFoRKC3XD" +
+        "FQvhqoam29F1rbl8FaYdPvhhZo8TfZQYUyUKwW+RbR44M5iHPx+ykieMe/C/4bcM3z8cwIbYI1aO" +
+        "gjQKS2MK9bs17xaDzeAh4sBKrskFGrDe+2dgvrSKdoakJhLTNTBSG6m+rzqMSCeQpafLKMSjTSSz" +
+        "+KoQ9bLyax8cbvViGGju0SlVhquloZmKOfHr8TukIoV64h3uCGFOVFtQjCYDOq6NbfRvMh14UVF5" +
+        "zgDIGczoD9dMoULWxBmniGSntoNgZM+QP6Id7DBasZGKfrHIAw3lHBqcvB5smemSu7F4itRoa3D8" +
+        "N7hhUEKAc+xA+8NKmXfiCBoHfPHTwDvt4IR7gWjeP3Xv5vitcKQ/MAfO5RwfzkYCXQ3FfjfzmsE1" +
+        "1IfLRDiBj+lhQSulhRVStKI88Che3M4JUNGKllrc0nt1pWa1vgzmUhhC4LSdm6trTHgyJnB6OcS9" +
+        "t2furYjK88j1AuB4921oxMxRm8c4Crq8Pyuf+n3YKi8Pl2BzBtw++0gj0ODlgwut8SrVj66/nvIB" +
+        "jN3kLVahR8nZrEFF6vTTmyXi761pzq9yOVqI57wJGx8o3Ygox1p+pWUPl1hQR7rrhUbgK/Q5wno9" +
+        "uJk07h3IZnNxE+/IKgeMTP/H4+jmyT4mhsexJ2BFHeiKF1KT/FMcJdSi+ZK5yoNVcYuY8aZbx0Ef" +
+        "lHorCXAmLFB0W6Cz4KPP01nD9YBB4olxiK1t7m0AU9zscdivNiuUaB5OIEr+JuZ6dNw=";    
+    /** 
+     * Defines the password for the keystore.
+     */
+    private static final String PASSWORD = "android";
+            
+    /** 
+     * Implements basically a dummy TrustManager. It stores the certificate
+     * chain it sees, so it can later be queried.
+     */
+    class TestTrustManager implements X509TrustManager {
+        
+        private X509Certificate[] chain;
+        
+        private String authType;
+        
+        public void checkClientTrusted(X509Certificate[] chain, String authType) {
+            this.chain = chain;
+            this.authType = authType;
+        }
+
+        public void checkServerTrusted(X509Certificate[] chain, String authType) {
+            this.chain = chain;
+            this.authType = authType;
+        }
+
+        public X509Certificate[] getAcceptedIssuers() {
+            return new X509Certificate[0];
+        }
+
+        public X509Certificate[] getChain() {
+            return chain;
+        }
+        
+        public String getAuthType() {
+            return authType;
+        }
+        
+    }
+    
+    /** 
+     * Implements a test SSL socket server. It wait for a connection on a given
+     * port, requests client authentication (if specified), and read 256 bytes
+     * from the socket. 
+     */
+    class TestServer implements Runnable {
+
+        public static final int CLIENT_AUTH_NONE = 0;
+
+        public static final int CLIENT_AUTH_WANTED = 1;
+
+        public static final int CLIENT_AUTH_NEEDED = 2;
+        
+        private TestTrustManager trustManager;
+
+        private Exception exception;
+
+        private int port;
+        
+        private int clientAuth;
+        
+        private boolean provideKeys;
+
+        public TestServer(int port, boolean provideKeys, int clientAuth) {
+            this.port = port;
+            this.clientAuth = clientAuth;
+            this.provideKeys = provideKeys;
+            
+            trustManager = new TestTrustManager(); 
+        }
+        
+        public void run() {
+            try {
+                KeyManager[] keyManagers = provideKeys
+                        ? getKeyManagers(SERVER_KEYS_BKS) : null;
+                TrustManager[] trustManagers = new TrustManager[] {
+                        trustManager };
+
+                SSLContext sslContext = SSLContext.getInstance("TLS");
+                sslContext.init(keyManagers, trustManagers, null);
+                
+                SSLServerSocket serverSocket
+                        = (SSLServerSocket) sslContext.getServerSocketFactory()
+                        .createServerSocket();
+                
+                if (clientAuth == CLIENT_AUTH_WANTED) {
+                    serverSocket.setWantClientAuth(true);
+                } else if (clientAuth == CLIENT_AUTH_NEEDED) {
+                    serverSocket.setNeedClientAuth(true);
+                } else {
+                    serverSocket.setWantClientAuth(false);
+                }
+                
+                serverSocket.bind(new InetSocketAddress(port));
+                
+                SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
+
+                InputStream stream = clientSocket.getInputStream();
+
+                for (int i = 0; i < 256; i++) {
+                    int j = stream.read();
+                    if (i != j) {
+                        throw new RuntimeException("Error reading socket,"
+                                + " expected " + i + ", got " + j);
+                    }
+                }
+                
+                stream.close();
+                clientSocket.close();
+                serverSocket.close();
+                
+            } catch (Exception ex) {
+                exception = ex;
+            }
+        }
+
+        public Exception getException() {
+            return exception;
+        }
+        
+        public X509Certificate[] getChain() {
+            return trustManager.getChain();
+        }
+        
+    }
+
+    /** 
+     * Implements a test SSL socket client. It open a connection to localhost on
+     * a given port and writes 256 bytes to the socket. 
+     */
+    class TestClient implements Runnable {
+        
+        private TestTrustManager trustManager;
+
+        private Exception exception;
+        
+        private int port;
+        
+        private boolean provideKeys;
+        
+        public TestClient(int port, boolean provideKeys) {
+            this.port = port;
+            this.provideKeys = provideKeys;
+            
+            trustManager = new TestTrustManager(); 
+        }
+        
+        public void run() {
+            try {
+                KeyManager[] keyManagers = provideKeys
+                        ? getKeyManagers(CLIENT_KEYS_BKS) : null;
+                TrustManager[] trustManagers = new TrustManager[] {
+                        trustManager };
+
+                SSLContext sslContext = SSLContext.getInstance("TLS");
+                sslContext.init(keyManagers, trustManagers, null);
+                
+                SSLSocket socket = (SSLSocket) sslContext.getSocketFactory()
+                        .createSocket();
+
+                socket.connect(new InetSocketAddress(port));
+                socket.startHandshake();
+
+                OutputStream stream = socket.getOutputStream();
+                
+                for (int i = 0; i < 256; i++) {
+                    stream.write(i);
+                }
+                
+                stream.flush();
+                stream.close();
+                socket.close();
+                
+            } catch (Exception ex) {
+                exception = ex;
+            }
+        }
+
+        public Exception getException() {
+            return exception;
+        }
+
+        public X509Certificate[] getChain() {
+            return trustManager.getChain();
+        }
+        
+    }
+    
+    /**
+     * Loads a keystore from a base64-encoded String. Returns the KeyManager[]
+     * for the result.
+     */
+    private KeyManager[] getKeyManagers(String keys) throws Exception {
+        byte[] bytes = new Base64().decode(keys.getBytes());                    
+        InputStream inputStream = new ByteArrayInputStream(bytes);
+        
+        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+        keyStore.load(inputStream, PASSWORD.toCharArray());
+        inputStream.close();
+        
+        String algorithm = KeyManagerFactory.getDefaultAlgorithm();
+        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
+        keyManagerFactory.init(keyStore, PASSWORD.toCharArray());
+        
+        return keyManagerFactory.getKeyManagers();
+    }
+
+    /**
+     * Implements the actual test case. Launches a server and a client, requires
+     * client authentication and checks the certificates afterwards (not in the
+     * usual sense, we just make sure that we got the expected certificates,
+     * because our self-signed test certificates are not valid.)
+     */
+    public void testClientAuth() {
+        try {
+            TestServer server = new TestServer(8088, true, TestServer.CLIENT_AUTH_WANTED);
+            TestClient client = new TestClient(8088, true);
+            
+            Thread serverThread = new Thread(server);
+            Thread clientThread = new Thread(client);
+            
+            serverThread.start();
+            clientThread.start();
+            
+            serverThread.join();
+            clientThread.join();
+            
+            // The server must have completed without an exception.
+            if (server.getException() != null) {
+                throw new RuntimeException(server.getException());
+            }
+
+            // The client must have completed without an exception.
+            if (client.getException() != null) {
+                throw new RuntimeException(client.getException());
+            }
+            
+            // Caution: The clientChain is the certificate chain from our
+            // client object. It contains the server certificates, of course!
+            X509Certificate[] clientChain = client.getChain();
+            assertTrue("Client cert chain must not be null", clientChain != null);
+            assertTrue("Client cert chain must not be empty", clientChain.length != 0);
+            assertEquals("CN=Test Server, OU=Android, O=Google, L=MTV, ST=California, C=US", clientChain[0].getSubjectDN().toString());
+            // Important part ------^
+            
+            // Caution: The serverChain is the certificate chain from our
+            // server object. It contains the client certificates, of course!
+            X509Certificate[] serverChain = server.getChain();
+            assertTrue("Server cert chain must not be null", serverChain != null);
+            assertTrue("Server cert chain must not be empty", serverChain.length != 0);
+            assertEquals("CN=Test Client, OU=Android, O=Google, L=MTV, ST=California, C=US", serverChain[0].getSubjectDN().toString());
+            // Important part ------^
+            
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    // -------------------------------------------------------------------------
+    private SSLSocket handshakeSocket;
+
+    private Exception handshakeException;
+
+    
+    public void testSSLHandshakeHangTimeout() {
+        
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    SSLSocket socket = (SSLSocket)clientFactory.createSocket(
+                            "www.heise.de", 80);
+                    socket.setSoTimeout(5000);
+                    socket.startHandshake();
+                    socket.close();
+                } catch (Exception ex) {
+                    handshakeException = ex;
+                }
+            }
+        };
+        
+        thread.start();
+        
+        try {
+            thread.join(10000);
+        } catch (InterruptedException ex) {
+            // Ignore.
+        }
+        
+        if (handshakeException == null) {
+            fail("SSL handshake should have failed.");
+        }
+    }
+
+    public void testSSLHandshakeHangClose() {
+        
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    handshakeSocket = (SSLSocket)clientFactory.createSocket(
+                            "www.heise.de", 80);
+                    handshakeSocket.startHandshake();
+                } catch (Exception ex) {
+                    handshakeException = ex;
+                }
+            }
+        };
+        
+        thread.start();
+
+        
+        try {
+            Thread.sleep(5000);
+            try {
+                handshakeSocket.close();
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            thread.join(5000);
+        } catch (InterruptedException ex) {
+            // Ignore.
+        }
+        
+        if (handshakeException == null) {
+            fail("SSL handshake should have failed.");
+        }
+    }
+
+    /**
+     * Tests our in-memory and persistent caching support.
+     */
+    public void testClientSessionCaching() throws IOException,
+            KeyManagementException {
+        SSLContextImpl context = new SSLContextImpl();
+
+        // Cache size = 2.
+        FakeClientSessionCache fakeCache = new FakeClientSessionCache();
+        context.engineInit(null, null, null, fakeCache, null);
+        SSLSocketFactory socketFactory = context.engineGetSocketFactory();
+        context.engineGetClientSessionContext().setSessionCacheSize(2);
+        makeRequests(socketFactory);
+        List<String> smallCacheOps = Arrays.asList(
+                "get www.fortify.net",
+                "put www.fortify.net",
+                "get www.paypal.com",
+                "put www.paypal.com",
+                "get www.yellownet.ch",
+                "put www.yellownet.ch",
+
+                // At this point, all in-memory cache requests should miss,
+                // but the sessions will still be in the persistent cache.
+                "get www.fortify.net",
+                "get www.paypal.com",
+                "get www.yellownet.ch"
+        );
+        assertEquals(smallCacheOps, fakeCache.ops);
+
+        // Cache size = 3.
+        fakeCache = new FakeClientSessionCache();
+        context.engineInit(null, null, null, fakeCache, null);
+        socketFactory = context.engineGetSocketFactory();
+        context.engineGetClientSessionContext().setSessionCacheSize(3);
+        makeRequests(socketFactory);
+        List<String> bigCacheOps = Arrays.asList(
+                "get www.fortify.net",
+                "put www.fortify.net",
+                "get www.paypal.com",
+                "put www.paypal.com",
+                "get www.yellownet.ch",
+                "put www.yellownet.ch"
+
+                // At this point, all results should be in the in-memory
+                // cache, and the persistent cache shouldn't be hit anymore.
+        );
+        assertEquals(bigCacheOps, fakeCache.ops);
+
+        // Cache size = 4.
+        fakeCache = new FakeClientSessionCache();
+        context.engineInit(null, null, null, fakeCache, null);
+        socketFactory = context.engineGetSocketFactory();
+        context.engineGetClientSessionContext().setSessionCacheSize(4);
+        makeRequests(socketFactory);
+        assertEquals(bigCacheOps, fakeCache.ops);
+    }
+
+    /**
+     * Executes sequence of requests twice using given socket factory.
+     */
+    private void makeRequests(SSLSocketFactory socketFactory)
+            throws IOException {
+        for (int i = 0; i < 2; i++) {
+            fetch(socketFactory, "www.fortify.net", 443, true, "/sslcheck.html",
+                    1, 1, 0, 60);
+            fetch(socketFactory, "www.paypal.com", 443, true, "/",
+                    1, 1, 0, 60);
+            fetch(socketFactory, "www.yellownet.ch", 443, true, "/",
+                    1, 1, 0, 60);
+        }
+    }
+
+    /**
+     * Fake in the sense that it doesn't actually persist anything.
+     */
+    static class FakeClientSessionCache implements SSLClientSessionCache {
+
+        List<String> ops = new ArrayList<String>();
+        Map<String, byte[]> sessions = new HashMap<String, byte[]>();
+
+        public byte[] getSessionData(String host, int port) {
+            ops.add("get " + host);
+            return sessions.get(host);
+        }
+
+        public void putSessionData(SSLSession session, byte[] sessionData) {
+            String host = session.getPeerHost();
+            System.err.println("length: " + sessionData.length);
+            ops.add("put " + host);
+            sessions.put(host, sessionData);
+        }
+    }
+
+    public void testFileBasedClientSessionCache() throws IOException,
+            KeyManagementException {
+        SSLContextImpl context = new SSLContextImpl();
+        String tmpDir = System.getProperty("java.io.tmpdir");
+        if (tmpDir == null) {
+            fail("Please set 'java.io.tmpdir' system property.");
+        }
+        File cacheDir = new File(tmpDir
+                + "/" + SSLSocketTest.class.getName() + "/cache");
+        deleteDir(cacheDir);
+        SSLClientSessionCache fileCache
+                = FileClientSessionCache.usingDirectory(cacheDir);
+        try {
+            ClientSessionCacheProxy cacheProxy
+                    = new ClientSessionCacheProxy(fileCache);
+            context.engineInit(null, null, null, cacheProxy, null);
+            SSLSocketFactory socketFactory = context.engineGetSocketFactory();
+            context.engineGetClientSessionContext().setSessionCacheSize(1);
+            makeRequests(socketFactory);
+            List<String> expected = Arrays.asList(
+                    "unsuccessful get www.fortify.net",
+                    "put www.fortify.net",
+                    "unsuccessful get www.paypal.com",
+                    "put www.paypal.com",
+                    "unsuccessful get www.yellownet.ch",
+                    "put www.yellownet.ch",
+
+                    // At this point, all in-memory cache requests should miss,
+                    // but the sessions will still be in the persistent cache.
+                    "successful get www.fortify.net",
+                    "successful get www.paypal.com",
+                    "successful get www.yellownet.ch"
+            );
+            assertEquals(expected, cacheProxy.ops);
+
+            // Try again now that file-based cache is populated.
+            fileCache = FileClientSessionCache.usingDirectory(cacheDir);
+            cacheProxy = new ClientSessionCacheProxy(fileCache);
+            context.engineInit(null, null, null, cacheProxy, null);
+            socketFactory = context.engineGetSocketFactory();
+            context.engineGetClientSessionContext().setSessionCacheSize(1);
+            makeRequests(socketFactory);
+            expected = Arrays.asList(
+                    "successful get www.fortify.net",
+                    "successful get www.paypal.com",
+                    "successful get www.yellownet.ch",
+                    "successful get www.fortify.net",
+                    "successful get www.paypal.com",
+                    "successful get www.yellownet.ch"
+            );
+            assertEquals(expected, cacheProxy.ops);
+        } finally {
+            deleteDir(cacheDir);
+        }
+    }
+
+    private static void deleteDir(File directory) {
+        if (!directory.exists()) {
+            return;
+        }
+        for (File file : directory.listFiles()) {
+            file.delete();
+        }
+        directory.delete();
+    }
+
+    static class ClientSessionCacheProxy implements SSLClientSessionCache {
+
+        final SSLClientSessionCache delegate;
+        final List<String> ops = new ArrayList<String>();
+
+        ClientSessionCacheProxy(SSLClientSessionCache delegate) {
+            this.delegate = delegate;
+        }
+
+        public byte[] getSessionData(String host, int port) {
+            byte[] sessionData = delegate.getSessionData(host, port);
+            ops.add((sessionData == null ? "unsuccessful" : "successful")
+                    + " get " + host);
+            return sessionData;
+        }
+
+        public void putSessionData(SSLSession session, byte[] sessionData) {
+            delegate.putSessionData(session, sessionData);
+            ops.add("put " + session.getPeerHost());
+        }
+    }
+
+    public static void main(String[] args) throws KeyManagementException, IOException {
+        new SSLSocketTest().testFileBasedClientSessionCache();
+    }
+}
diff --git a/tests/CoreTests/android/core/Sha1Test.java b/tests/CoreTests/android/core/Sha1Test.java
new file mode 100644
index 0000000..dcd4c04
--- /dev/null
+++ b/tests/CoreTests/android/core/Sha1Test.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import android.security.MessageDigest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+/**
+ * Tests SHA1 message digest algorithm.
+ */
+public class Sha1Test extends TestCase {
+    class TestData {
+        private String input;
+        private String result;
+
+        public TestData(String i, String r) {
+            input = i;
+            result = r;
+        }
+    }
+
+    TestData[] mTestData = new TestData[]{
+            new TestData("abc", "a9993e364706816aba3e25717850c26c9cd0d89d"),
+            new TestData("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+                    "84983e441c3bd26ebaae4aa1f95129e5e54670f1")
+    };
+
+    @SmallTest
+    public void testSha1() throws Exception {
+        MessageDigest digest = MessageDigest.getInstance("SHA-1");
+
+        int numTests = mTestData.length;
+        for (int i = 0; i < numTests; i++) {
+            digest.update(mTestData[i].input.getBytes());
+            byte[] hash = digest.digest();
+            String encodedHash = encodeHex(hash);
+            assertEquals(encodedHash, mTestData[i].result);
+        }
+    }
+
+    private static String encodeHex(byte[] bytes) {
+        StringBuffer hex = new StringBuffer(bytes.length * 2);
+
+        for (int i = 0; i < bytes.length; i++) {
+            if (((int) bytes[i] & 0xff) < 0x10) {
+                hex.append("0");
+            }
+            hex.append(Integer.toString((int) bytes[i] & 0xff, 16));
+        }
+
+        return hex.toString();
+    }
+}
+
diff --git a/tests/CoreTests/android/core/SocketTest.java b/tests/CoreTests/android/core/SocketTest.java
new file mode 100644
index 0000000..b64c156
--- /dev/null
+++ b/tests/CoreTests/android/core/SocketTest.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.Semaphore;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Regression tests for various socket related problems. And a few general
+ * socket tests.
+ */
+public class SocketTest extends TestCase {
+
+    private static final String NON_EXISTING_ADDRESS = "123.123.123.123";
+
+    private static final String KNOW_GOOD_ADDRESS = "209.85.129.147";
+
+    private static final String PACKAGE_DROPPING_ADDRESS = "191.167.0.1";
+    
+    // Test for basic bind/connect/accept behavior.
+    @SmallTest
+    public void testSocketSimple() throws Exception {
+        ServerSocket ss;
+        Socket s, s1;
+        int port;
+
+        IOException lastEx = null;
+
+        ss = new ServerSocket();
+
+        for (port = 9900; port < 9999; port++) {
+            try {
+                ss.bind(new InetSocketAddress("127.0.0.1", port));
+                lastEx = null;
+                break;
+            } catch (IOException ex) {
+                lastEx = ex;
+            }
+        }
+
+        if (lastEx != null) {
+            throw lastEx;
+        }
+
+        s = new Socket("127.0.0.1", port);
+
+        s1 = ss.accept();
+
+        s.getOutputStream().write(0xa5);
+
+        assertEquals(0xa5, s1.getInputStream().read());
+
+        s1.getOutputStream().write(0x5a);
+        assertEquals(0x5a, s.getInputStream().read());
+    }
+    
+    // Regression test for #820068: Wildcard address
+    @SmallTest
+    public void testWildcardAddress() throws Exception {
+        Socket s2 = new Socket();
+        s2.bind(new InetSocketAddress((InetAddress) null, 12345));
+        byte[] addr = s2.getLocalAddress().getAddress();
+        for (int i = 0; i < 4; i++) {
+            assertEquals("Not the wildcard address", 0, addr[i]);
+        }
+    }
+    
+    // Regression test for #865753: server sockets not closing properly
+    @SmallTest
+    public void testServerSocketClose() throws Exception {
+        ServerSocket s3 = new ServerSocket(23456);
+        s3.close();
+        ServerSocket s4 = new ServerSocket(23456);
+        s4.close();
+    }
+    
+    // Regression test for #876985: SO_REUSEADDR not working properly
+    
+    private Exception serverError = null;
+    
+    @LargeTest
+    public void testSetReuseAddress() throws IOException {
+        InetSocketAddress addr = new InetSocketAddress(8383);
+
+        final ServerSocket serverSock = new ServerSocket();
+        serverSock.setReuseAddress(true);
+        serverSock.bind(addr);
+
+        final Semaphore semThreadEnd = new Semaphore(0);
+        new Thread() {
+            @Override
+            public void run() {
+                try {
+                    Socket sock = serverSock.accept();
+                    sock.getInputStream().read();
+                    sock.close();
+                } catch (IOException e) {
+                    serverError = e;
+                }
+                semThreadEnd.release();
+            }
+        }.start();
+
+        // Give the server a bit of time for startup
+        try {
+            Thread.sleep(2000);
+        } catch (InterruptedException ex) {
+            // Ignored.
+        }
+        
+        Socket client = new Socket("localhost", 8383);
+        client.getOutputStream().write(1);
+        // Just leave this connection open from the client side. It will be
+        // closed from the server side so the server stays in the TIME_WAIT
+        // state for a while. setReuseAddress() should be able to handle this.
+
+        try {
+            semThreadEnd.acquire();
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        serverSock.close();
+
+        ServerSocket serverSock2 = new ServerSocket();
+        serverSock2.setReuseAddress(true);
+        serverSock2.bind(addr);
+        serverSock2.close();
+        
+        if (serverError != null) {
+            throw new RuntimeException("Server must complete without error", serverError);
+        }
+    }
+
+    // Regression for 916701, a wrong exception was thrown after timeout of
+    // a ServerSocket.
+    @LargeTest
+    public void testTimeoutException() throws IOException {
+        ServerSocket s = new ServerSocket(9800);
+        s.setSoTimeout(2000);
+        try {
+            s.accept();
+        } catch (SocketTimeoutException e) {
+            // this is ok.
+        }
+    }
+
+    // Regression for issue 1001980, openening a SocketChannel threw an Exception
+    @SmallTest
+    public void testNativeSocketChannelOpen() throws IOException {
+        SocketChannel.open();
+    }
+
+    // Regression test for issue 1018016, connecting ignored a set timeout.
+    @LargeTest
+    public void testSocketSetSOTimeout() throws IOException {
+        Socket sock = new Socket();
+        int timeout = 5000;
+        long start = System.currentTimeMillis();
+        try {
+            sock.connect(new InetSocketAddress(NON_EXISTING_ADDRESS, 80), timeout);
+        } catch (SocketTimeoutException e) {
+            // expected
+            long delay = System.currentTimeMillis() - start;
+            if (Math.abs(delay - timeout) > 1000) {
+                fail("timeout was not accurate. expected: " + timeout
+                        + " actual: " + delay + " miliseconds.");
+            }
+        } finally {
+            try {
+                sock.close();
+            } catch (IOException ioe) {
+                // ignore
+            }
+        }
+    }
+    
+    /**
+     * Regression test for 1062928: Dotted IP addresses (e.g., 192.168.100.1)
+     * appear to be broken in the M5 SDK.
+     * 
+     * Tests that a connection given a ip-addressv4 such as 192.168.100.100 does
+     * not fail - sdk m5 seems only to accept dns names instead of ip numbers.
+     * ip 209.85.129.147 (one address of www.google.com) on port 80 (http) is
+     * used to test the connection.
+     */
+
+// Commenting out this test since it is flaky, even at the best of times.  See
+// #1191317 for Info.
+    @Suppress
+    public void disable_testConnectWithIP4IPAddr() {
+        // call a Google Web server
+        InetSocketAddress scktAddrss = new InetSocketAddress(KNOW_GOOD_ADDRESS,
+                80);
+        Socket clntSckt = new Socket();
+        try {
+            clntSckt.connect(scktAddrss, 5000);
+        } catch (Throwable e) {
+            fail("connection problem:" + e.getClass().getName() + ": "
+                    + e.getMessage());
+        } finally {
+            try {
+                clntSckt.close();
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+    }
+
+    
+    // Regression test for #1058962: Socket.close() does not cause
+    // socket.connect() to return immediately.
+    private Socket client;
+    
+    private Exception error;
+    
+    private boolean connected;
+
+// This test isn't working now, but really should work.
+// TODO Enable this test again.
+
+    @Suppress
+    public void disable_testSocketConnectClose() {
+        try {
+            client = new Socket();
+            
+            new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        client.connect(new InetSocketAddress(PACKAGE_DROPPING_ADDRESS, 1357));
+                    } catch (Exception ex) {
+                        error = ex;
+                    }
+                    
+                    connected = true;
+                }
+            }.start();
+            
+            Thread.sleep(1000);
+            
+            Assert.assertNull("Connect must not fail immediately. Maybe try different address.", error);
+            Assert.assertFalse("Connect must not succeed. Maybe try different address.", connected);
+            
+            client.close();
+            
+            Thread.sleep(1000);
+
+            if (error == null) {
+                fail("Socket connect still ongoing");
+            } else if (!(error instanceof SocketException)) {
+                fail("Socket connect interrupted with wrong error: " + error.toString());
+            }
+            
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+            
+    }
+    
+}
diff --git a/tests/CoreTests/android/core/StreamTokenizerTest.java b/tests/CoreTests/android/core/StreamTokenizerTest.java
new file mode 100644
index 0000000..5013860
--- /dev/null
+++ b/tests/CoreTests/android/core/StreamTokenizerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Tests for the StreamTokenizer
+ */
+public class StreamTokenizerTest extends TestCase {
+    
+    @MediumTest
+    public void testStreamTokenizer() throws Exception {
+        String str = "Testing 12345 \n alpha \r\n omega";
+        String strb = "-3.8 'BLIND mice' \r sEe /* how */ they run";
+        StringReader aa = new StringReader(str);
+        StringReader ba = new StringReader(strb);
+        StreamTokenizer a = new StreamTokenizer(aa);
+        StreamTokenizer b = new StreamTokenizer(ba);
+
+        assertEquals(1, a.lineno());
+        assertEquals(StreamTokenizer.TT_WORD, a.nextToken());
+        assertEquals("Token[Testing], line 1", a.toString());
+        assertEquals(StreamTokenizer.TT_NUMBER, a.nextToken());
+        assertEquals("Token[n=12345.0], line 1", a.toString());
+        assertEquals(StreamTokenizer.TT_WORD, a.nextToken());
+        assertEquals("Token[alpha], line 2", a.toString());
+        assertEquals(StreamTokenizer.TT_WORD, a.nextToken());
+        assertEquals("Token[omega], line 3", a.toString());
+        assertEquals(StreamTokenizer.TT_EOF, a.nextToken());
+        assertEquals("Token[EOF], line 3", a.toString());
+
+        b.commentChar('u');
+        b.eolIsSignificant(true);
+        b.lowerCaseMode(true);
+        b.ordinaryChar('y');
+        b.slashStarComments(true);
+
+        assertEquals(StreamTokenizer.TT_NUMBER, b.nextToken());
+        assertEquals(-3.8, b.nval);
+        assertEquals("Token[n=-3.8], line 1", b.toString());
+        assertEquals(39, b.nextToken()); // '
+        assertEquals("Token[BLIND mice], line 1", b.toString());
+        assertEquals(10, b.nextToken()); // \n
+        assertEquals("Token[EOL], line 2", b.toString());
+        assertEquals(StreamTokenizer.TT_WORD, b.nextToken());
+        assertEquals("Token[see], line 2", b.toString());
+        assertEquals(StreamTokenizer.TT_WORD, b.nextToken());
+        assertEquals("Token[the], line 2", b.toString());
+        assertEquals(121, b.nextToken()); // y
+        assertEquals("Token['y'], line 2", b.toString());
+        assertEquals(StreamTokenizer.TT_WORD, b.nextToken());
+        assertEquals("Token[r], line 2", b.toString());
+        assertEquals(StreamTokenizer.TT_EOF, b.nextToken());
+        assertEquals("Token[EOF], line 2", b.toString());
+
+        // A harmony regression test
+        byte[] data = new byte[]{(byte) '-'};
+        StreamTokenizer tokenizer = new StreamTokenizer(new ByteArrayInputStream(data));
+        tokenizer.nextToken();
+        String result = tokenizer.toString();
+        assertEquals("Token['-'], line 1", result);
+
+        // another harmony regression test
+        byte[] data2 = new byte[]{(byte) '"',
+                (byte) 'H',
+                (byte) 'e',
+                (byte) 'l',
+                (byte) 'l',
+                (byte) 'o',
+                (byte) '"'};
+        StreamTokenizer tokenizer2 = new StreamTokenizer(new ByteArrayInputStream(data2));
+        tokenizer2.nextToken();
+        result = tokenizer2.toString();
+        assertEquals("Token[Hello], line 1", result);
+    }
+}
diff --git a/tests/CoreTests/android/core/StrictMathTest.java b/tests/CoreTests/android/core/StrictMathTest.java
new file mode 100644
index 0000000..92e6cb6
--- /dev/null
+++ b/tests/CoreTests/android/core/StrictMathTest.java
@@ -0,0 +1,855 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class StrictMathTest extends TestCase {
+
+    private final double HYP = StrictMath.sqrt(2.0);
+
+    private final double OPP = 1.0;
+
+    private final double ADJ = 1.0;
+
+    /* Required to make previous preprocessor flags work - do not remove */
+    int unused = 0;
+
+    /**
+     * @tests java.lang.StrictMath#abs(double)
+     */
+    @SmallTest
+    public void testAbsD() {
+        // Test for method double java.lang.StrictMath.abs(double)
+
+        assertTrue("Incorrect double abs value",
+                (StrictMath.abs(-1908.8976) == 1908.8976));
+        assertTrue("Incorrect double abs value",
+                (StrictMath.abs(1908.8976) == 1908.8976));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#abs(float)
+     */
+    @SmallTest
+    public void testAbsF() {
+        // Test for method float java.lang.StrictMath.abs(float)
+        assertTrue("Incorrect float abs value",
+                (StrictMath.abs(-1908.8976f) == 1908.8976f));
+        assertTrue("Incorrect float abs value",
+                (StrictMath.abs(1908.8976f) == 1908.8976f));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#abs(int)
+     */
+    @SmallTest
+    public void testAbsI() {
+        // Test for method int java.lang.StrictMath.abs(int)
+        assertTrue("Incorrect int abs value",
+                (StrictMath.abs(-1908897) == 1908897));
+        assertTrue("Incorrect int abs value",
+                (StrictMath.abs(1908897) == 1908897));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#abs(long)
+     */
+    @SmallTest
+    public void testAbsJ() {
+        // Test for method long java.lang.StrictMath.abs(long)
+        assertTrue("Incorrect long abs value", (StrictMath
+                .abs(-19088976000089L) == 19088976000089L));
+        assertTrue("Incorrect long abs value",
+                (StrictMath.abs(19088976000089L) == 19088976000089L));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#acos(double)
+     */
+    @SmallTest
+    public void testAcosD() {
+        // Test for method double java.lang.StrictMath.acos(double)
+        assertTrue("Returned incorrect arc cosine", StrictMath.cos(StrictMath
+                .acos(ADJ / HYP)) == ADJ / HYP);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#asin(double)
+     */
+    @SmallTest
+    public void testAsinD() {
+        // Test for method double java.lang.StrictMath.asin(double)
+        assertTrue("Returned incorrect arc sine", StrictMath.sin(StrictMath
+                .asin(OPP / HYP)) == OPP / HYP);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#atan(double)
+     */
+    @SmallTest
+    public void testAtanD() {
+        // Test for method double java.lang.StrictMath.atan(double)
+        double answer = StrictMath.tan(StrictMath.atan(1.0));
+        assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+                && answer >= 9.9999999999999983E-1);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#atan2(double,double)
+     */
+    @SmallTest
+    public void testAtan2DD() {
+        // Test for method double java.lang.StrictMath.atan2(double, double)
+        double answer = StrictMath.atan(StrictMath.tan(1.0));
+        assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+                && answer >= 9.9999999999999983E-1);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#cbrt(double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testCbrtD() {
+        // Test for special situations
+        assertTrue("Should return Double.NaN", Double.isNaN(StrictMath
+                .cbrt(Double.NaN)));
+        assertEquals("Should return Double.POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath
+                .cbrt(Double.POSITIVE_INFINITY));
+        assertEquals("Should return Double.NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, StrictMath
+                .cbrt(Double.NEGATIVE_INFINITY));
+        assertEquals(Double.doubleToLongBits(0.0), Double
+                .doubleToLongBits(StrictMath.cbrt(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(StrictMath.cbrt(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(StrictMath.cbrt(-0.0)));
+
+        assertEquals("Should return 3.0", 3.0, StrictMath.cbrt(27.0));
+        assertEquals("Should return 23.111993172558684", 23.111993172558684,
+                StrictMath.cbrt(12345.6));
+        assertEquals("Should return 5.643803094122362E102",
+                5.643803094122362E102, StrictMath.cbrt(Double.MAX_VALUE));
+        assertEquals("Should return 0.01", 0.01, StrictMath.cbrt(0.000001));
+
+        assertEquals("Should return -3.0", -3.0, StrictMath.cbrt(-27.0));
+        assertEquals("Should return -23.111993172558684", -23.111993172558684,
+                StrictMath.cbrt(-12345.6));
+        assertEquals("Should return 1.7031839360032603E-108",
+                1.7031839360032603E-108, StrictMath.cbrt(Double.MIN_VALUE));
+        assertEquals("Should return -0.01", -0.01, StrictMath.cbrt(-0.000001));
+
+        try {
+            StrictMath.cbrt((Double) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            //expected
+        }
+    }
+
+    /**
+     * @tests java.lang.StrictMath#ceil(double)
+     */
+    @SmallTest
+    public void testCeilD() {
+        // Test for method double java.lang.StrictMath.ceil(double)
+        assertEquals("Incorrect ceiling for double",
+                79, StrictMath.ceil(78.89), 0.0);
+        assertEquals("Incorrect ceiling for double",
+                -78, StrictMath.ceil(-78.89), 0.0);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#cos(double)
+     */
+    @SmallTest
+    public void testCosD() {
+        // Test for method double java.lang.StrictMath.cos(double)
+
+        assertTrue("Returned incorrect cosine", StrictMath.cos(StrictMath
+                .acos(ADJ / HYP)) == ADJ / HYP);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#cosh(double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testCosh_D() {
+        // Test for special situations        
+        assertTrue("Should return NaN", Double.isNaN(StrictMath
+                .cosh(Double.NaN)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath
+                .cosh(Double.POSITIVE_INFINITY));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath
+                .cosh(Double.NEGATIVE_INFINITY));
+        assertEquals("Should return 1.0", 1.0, StrictMath.cosh(+0.0));
+        assertEquals("Should return 1.0", 1.0, StrictMath.cosh(-0.0));
+
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.cosh(1234.56));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.cosh(-1234.56));
+        assertEquals("Should return 1.0000000000005", 1.0000000000005,
+                StrictMath.cosh(0.000001));
+        assertEquals("Should return 1.0000000000005", 1.0000000000005,
+                StrictMath.cosh(-0.000001));
+        assertEquals("Should return 5.212214351945598", 5.212214351945598,
+                StrictMath.cosh(2.33482));
+
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.cosh(Double.MAX_VALUE));
+        assertEquals("Should return 1.0", 1.0, StrictMath
+                .cosh(Double.MIN_VALUE));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#exp(double)
+     */
+    @SmallTest
+    public void testExpD() {
+        // Test for method double java.lang.StrictMath.exp(double)
+        assertTrue("Incorrect answer returned for simple power", StrictMath
+                .abs(StrictMath.exp(4D) - StrictMath.E * StrictMath.E
+                        * StrictMath.E * StrictMath.E) < 0.1D);
+        assertTrue("Incorrect answer returned for larger power", StrictMath
+                .log(StrictMath.abs(StrictMath.exp(5.5D)) - 5.5D) < 10.0D);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#expm1(double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testExpm1D() {
+        //Test for special cases        
+        assertTrue("Should return NaN", Double.isNaN(StrictMath.expm1(Double.NaN)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.expm1(Double.POSITIVE_INFINITY));
+        assertEquals("Should return -1.0", -1.0, StrictMath
+                .expm1(Double.NEGATIVE_INFINITY));
+        assertEquals(Double.doubleToLongBits(0.0), Double
+                .doubleToLongBits(StrictMath.expm1(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(StrictMath.expm1(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(StrictMath.expm1(-0.0)));
+
+        assertEquals("Should return -9.999950000166666E-6",
+                -9.999950000166666E-6, StrictMath.expm1(-0.00001));
+        assertEquals("Should return 1.0145103074469635E60",
+                1.0145103074469635E60, StrictMath.expm1(138.16951162));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath
+                .expm1(123456789123456789123456789.4521584223));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.expm1(Double.MAX_VALUE));
+        assertEquals("Should return MIN_VALUE", Double.MIN_VALUE, StrictMath
+                .expm1(Double.MIN_VALUE));
+
+    }
+
+    /**
+     * @tests java.lang.StrictMath#floor(double)
+     */
+    @SmallTest
+    public void testFloorD() {
+        // Test for method double java.lang.StrictMath.floor(double)
+        assertEquals("Incorrect floor for double",
+                78, StrictMath.floor(78.89), 0.0);
+        assertEquals("Incorrect floor for double",
+                -79, StrictMath.floor(-78.89), 0.0);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#hypot(double,double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testHypotDD() {
+        // Test for special cases
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.hypot(Double.POSITIVE_INFINITY,
+                1.0));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.hypot(Double.NEGATIVE_INFINITY,
+                123.324));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.hypot(-758.2587,
+                Double.POSITIVE_INFINITY));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.hypot(5687.21,
+                Double.NEGATIVE_INFINITY));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.hypot(Double.POSITIVE_INFINITY,
+                Double.NEGATIVE_INFINITY));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.hypot(Double.NEGATIVE_INFINITY,
+                Double.POSITIVE_INFINITY));
+        assertTrue("Should return NaN", Double.isNaN(StrictMath.hypot(Double.NaN,
+                2342301.89843)));
+        assertTrue("Should return NaN", Double.isNaN(StrictMath.hypot(-345.2680,
+                Double.NaN)));
+
+        assertEquals("Should return 2396424.905416697", 2396424.905416697, StrictMath
+                .hypot(12322.12, -2396393.2258));
+        assertEquals("Should return 138.16958070558556", 138.16958070558556,
+                StrictMath.hypot(-138.16951162, 0.13817035864));
+        assertEquals("Should return 1.7976931348623157E308",
+                1.7976931348623157E308, StrictMath.hypot(Double.MAX_VALUE, 211370.35));
+        assertEquals("Should return 5413.7185", 5413.7185, StrictMath.hypot(
+                -5413.7185, Double.MIN_VALUE));
+
+    }
+
+    /**
+     * @tests java.lang.StrictMath#IEEEremainder(double,double)
+     */
+    @SmallTest
+    public void testIEEEremainderDD() {
+        // Test for method double java.lang.StrictMath.IEEEremainder(double,
+        // double)
+        assertEquals("Incorrect remainder returned", 0.0, StrictMath.IEEEremainder(
+                1.0, 1.0), 0.0);
+        assertTrue(
+                "Incorrect remainder returned",
+                StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631647E-2
+                        || StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#log(double)
+     */
+    @SmallTest
+    public void testLogD() {
+        // Test for method double java.lang.StrictMath.log(double)
+        for (double d = 10; d >= -10; d -= 0.5) {
+            double answer = StrictMath.log(StrictMath.exp(d));
+            assertTrue("Answer does not equal expected answer for d = " + d
+                    + " answer = " + answer,
+                    StrictMath.abs(answer - d) <= StrictMath
+                            .abs(d * 0.00000001));
+        }
+    }
+
+    /**
+     * @tests java.lang.StrictMath#log10(double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testLog10D() {
+        // Test for special cases        
+        assertTrue("Should return NaN", Double.isNaN(StrictMath
+                .log10(Double.NaN)));
+        assertTrue("Should return NaN", Double.isNaN(StrictMath
+                .log10(-2541.05745687234187532)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath
+                .log10(Double.POSITIVE_INFINITY));
+        assertEquals("Should return NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, StrictMath.log10(0.0));
+        assertEquals("Should return NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, StrictMath.log10(+0.0));
+        assertEquals("Should return NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, StrictMath.log10(-0.0));
+        assertEquals("Should return 14.0", 14.0, StrictMath.log10(StrictMath
+                .pow(10, 14)));
+
+        assertEquals("Should return 3.7389561269540406", 3.7389561269540406,
+                StrictMath.log10(5482.2158));
+        assertEquals("Should return 14.661551142893833", 14.661551142893833,
+                StrictMath.log10(458723662312872.125782332587));
+        assertEquals("Should return -0.9083828622192334", -0.9083828622192334,
+                StrictMath.log10(0.12348583358871));
+        assertEquals("Should return 308.25471555991675", 308.25471555991675,
+                StrictMath.log10(Double.MAX_VALUE));
+        assertEquals("Should return -323.3062153431158", -323.3062153431158,
+                StrictMath.log10(Double.MIN_VALUE));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#log1p(double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testLog1pD() {
+        // Test for special cases
+        assertTrue("Should return NaN", Double.isNaN(StrictMath
+                .log1p(Double.NaN)));
+        assertTrue("Should return NaN", Double.isNaN(StrictMath
+                .log1p(-32.0482175)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath
+                .log1p(Double.POSITIVE_INFINITY));
+        assertEquals(Double.doubleToLongBits(0.0), Double
+                .doubleToLongBits(StrictMath.log1p(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(StrictMath.log1p(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(StrictMath.log1p(-0.0)));
+
+        assertEquals("Should return -0.2941782295312541", -0.2941782295312541,
+                StrictMath.log1p(-0.254856327));
+        assertEquals("Should return 7.368050685564151", 7.368050685564151,
+                StrictMath.log1p(1583.542));
+        assertEquals("Should return 0.4633708685409921", 0.4633708685409921,
+                StrictMath.log1p(0.5894227));
+        assertEquals("Should return 709.782712893384", 709.782712893384,
+                StrictMath.log1p(Double.MAX_VALUE));
+        assertEquals("Should return Double.MIN_VALUE", Double.MIN_VALUE,
+                StrictMath.log1p(Double.MIN_VALUE));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#max(double,double)
+     */
+    @SmallTest
+    public void testMaxDD() {
+        // Test for method double java.lang.StrictMath.max(double, double)
+        assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(
+                -1908897.6000089, 1908897.6000089), 0D);
+        assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(2.0,
+                1908897.6000089), 0D);
+        assertEquals("Incorrect double max value", -2.0, StrictMath.max(-2.0,
+                -1908897.6000089), 0D);
+
+    }
+
+    /**
+     * @tests java.lang.StrictMath#max(float,float)
+     */
+    @SmallTest
+    public void testMaxFF() {
+        // Test for method float java.lang.StrictMath.max(float, float)
+        assertTrue("Incorrect float max value", StrictMath.max(-1908897.600f,
+                1908897.600f) == 1908897.600f);
+        assertTrue("Incorrect float max value", StrictMath.max(2.0f,
+                1908897.600f) == 1908897.600f);
+        assertTrue("Incorrect float max value", StrictMath.max(-2.0f,
+                -1908897.600f) == -2.0f);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#max(int,int)
+     */
+    @SmallTest
+    public void testMaxII() {
+        // Test for method int java.lang.StrictMath.max(int, int)
+        assertEquals("Incorrect int max value", 19088976, StrictMath.max(-19088976,
+                19088976));
+        assertEquals("Incorrect int max value",
+                19088976, StrictMath.max(20, 19088976));
+        assertEquals("Incorrect int max value",
+                -20, StrictMath.max(-20, -19088976));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#max(long,long)
+     */
+    @SmallTest
+    public void testMaxJJ() {
+        // Test for method long java.lang.StrictMath.max(long, long)
+        assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(-19088976000089L,
+                19088976000089L));
+        assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(20,
+                19088976000089L));
+        assertEquals("Incorrect long max value", -20, StrictMath.max(-20,
+                -19088976000089L));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#min(double,double)
+     */
+    @SmallTest
+    public void testMinDD() {
+        // Test for method double java.lang.StrictMath.min(double, double)
+        assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(
+                -1908897.6000089, 1908897.6000089), 0D);
+        assertEquals("Incorrect double min value", 2.0, StrictMath.min(2.0,
+                1908897.6000089), 0D);
+        assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(-2.0,
+                -1908897.6000089), 0D);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#min(float,float)
+     */
+    @SmallTest
+    public void testMinFF() {
+        // Test for method float java.lang.StrictMath.min(float, float)
+        assertTrue("Incorrect float min value", StrictMath.min(-1908897.600f,
+                1908897.600f) == -1908897.600f);
+        assertTrue("Incorrect float min value", StrictMath.min(2.0f,
+                1908897.600f) == 2.0f);
+        assertTrue("Incorrect float min value", StrictMath.min(-2.0f,
+                -1908897.600f) == -1908897.600f);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#min(int,int)
+     */
+    @SmallTest
+    public void testMinII() {
+        // Test for method int java.lang.StrictMath.min(int, int)
+        assertEquals("Incorrect int min value", -19088976, StrictMath.min(-19088976,
+                19088976));
+        assertEquals("Incorrect int min value",
+                20, StrictMath.min(20, 19088976));
+        assertEquals("Incorrect int min value",
+                -19088976, StrictMath.min(-20, -19088976));
+
+    }
+
+    /**
+     * @tests java.lang.StrictMath#min(long,long)
+     */
+    @SmallTest
+    public void testMinJJ() {
+        // Test for method long java.lang.StrictMath.min(long, long)
+        assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-19088976000089L,
+                19088976000089L));
+        assertEquals("Incorrect long min value", 20, StrictMath.min(20,
+                19088976000089L));
+        assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-20,
+                -19088976000089L));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#pow(double,double)
+     */
+    @SmallTest
+    public void testPowDD() {
+        // Test for method double java.lang.StrictMath.pow(double, double)
+        assertTrue("pow returned incorrect value",
+                (long) StrictMath.pow(2, 8) == 256l);
+        assertTrue("pow returned incorrect value",
+                StrictMath.pow(2, -8) == 0.00390625d);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#rint(double)
+     */
+    @SmallTest
+    public void testRintD() {
+        // Test for method double java.lang.StrictMath.rint(double)
+        assertEquals("Failed to round properly - up to odd",
+                3.0, StrictMath.rint(2.9), 0D);
+        assertTrue("Failed to round properly - NaN", Double.isNaN(StrictMath
+                .rint(Double.NaN)));
+        assertEquals("Failed to round properly down  to even", 2.0, StrictMath
+                .rint(2.1), 0D);
+        assertTrue("Failed to round properly " + 2.5 + " to even", StrictMath
+                .rint(2.5) == 2.0);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#round(double)
+     */
+    @SmallTest
+    public void testRoundD() {
+        // Test for method long java.lang.StrictMath.round(double)
+        assertEquals("Incorrect rounding of a float",
+                -91, StrictMath.round(-90.89d));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#round(float)
+     */
+    @SmallTest
+    public void testRoundF() {
+        // Test for method int java.lang.StrictMath.round(float)
+        assertEquals("Incorrect rounding of a float",
+                -91, StrictMath.round(-90.89f));
+    }
+
+    /**
+     * @tests java.lang.StrictMath#signum(double)
+     */
+    @SmallTest
+    public void testSignumD() {
+        assertTrue(Double.isNaN(StrictMath.signum(Double.NaN)));
+        assertEquals(Double.doubleToLongBits(0.0), Double
+                .doubleToLongBits(StrictMath.signum(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(StrictMath.signum(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(StrictMath.signum(-0.0)));
+
+        assertEquals(1.0, StrictMath.signum(253681.2187962), 0D);
+        assertEquals(-1.0, StrictMath.signum(-125874693.56), 0D);
+        assertEquals(1.0, StrictMath.signum(1.2587E-308), 0D);
+        assertEquals(-1.0, StrictMath.signum(-1.2587E-308), 0D);
+
+        assertEquals(1.0, StrictMath.signum(Double.MAX_VALUE), 0D);
+        assertEquals(1.0, StrictMath.signum(Double.MIN_VALUE), 0D);
+        assertEquals(-1.0, StrictMath.signum(-Double.MAX_VALUE), 0D);
+        assertEquals(-1.0, StrictMath.signum(-Double.MIN_VALUE), 0D);
+        assertEquals(1.0, StrictMath.signum(Double.POSITIVE_INFINITY), 0D);
+        assertEquals(-1.0, StrictMath.signum(Double.NEGATIVE_INFINITY), 0D);
+
+    }
+
+    /**
+     * @tests java.lang.StrictMath#signum(float)
+     */
+    @SmallTest
+    public void testSignumF() {
+        assertTrue(Float.isNaN(StrictMath.signum(Float.NaN)));
+        assertEquals(Float.floatToIntBits(0.0f), Float
+                .floatToIntBits(StrictMath.signum(0.0f)));
+        assertEquals(Float.floatToIntBits(+0.0f), Float
+                .floatToIntBits(StrictMath.signum(+0.0f)));
+        assertEquals(Float.floatToIntBits(-0.0f), Float
+                .floatToIntBits(StrictMath.signum(-0.0f)));
+
+        assertEquals(1.0f, StrictMath.signum(253681.2187962f), 0f);
+        assertEquals(-1.0f, StrictMath.signum(-125874693.56f), 0f);
+        assertEquals(1.0f, StrictMath.signum(1.2587E-11f), 0f);
+        assertEquals(-1.0f, StrictMath.signum(-1.2587E-11f), 0f);
+
+        assertEquals(1.0f, StrictMath.signum(Float.MAX_VALUE), 0f);
+        assertEquals(1.0f, StrictMath.signum(Float.MIN_VALUE), 0f);
+        assertEquals(-1.0f, StrictMath.signum(-Float.MAX_VALUE), 0f);
+        assertEquals(-1.0f, StrictMath.signum(-Float.MIN_VALUE), 0f);
+        assertEquals(1.0f, StrictMath.signum(Float.POSITIVE_INFINITY), 0f);
+        assertEquals(-1.0f, StrictMath.signum(Float.NEGATIVE_INFINITY), 0f);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#sin(double)
+     */
+    @SmallTest
+    public void testSinD() {
+        // Test for method double java.lang.StrictMath.sin(double)
+        assertTrue("Returned incorrect sine", StrictMath.sin(StrictMath
+                .asin(OPP / HYP)) == OPP / HYP);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#sinh(double)
+     */
+    @SmallTest
+    public void testSinhD() {
+        // Test for special situations
+        assertTrue(Double.isNaN(StrictMath.sinh(Double.NaN)));
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath
+                .sinh(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Should return NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, StrictMath
+                .sinh(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals(Double.doubleToLongBits(0.0), Double
+                .doubleToLongBits(StrictMath.sinh(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(StrictMath.sinh(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(StrictMath.sinh(-0.0)));
+
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.sinh(1234.56), 0D);
+        assertEquals("Should return NEGATIVE_INFINITY",
+                Double.NEGATIVE_INFINITY, StrictMath.sinh(-1234.56), 0D);
+        assertEquals("Should return 1.0000000000001666E-6",
+                1.0000000000001666E-6, StrictMath.sinh(0.000001), 0D);
+        assertEquals("Should return -1.0000000000001666E-6",
+                -1.0000000000001666E-6, StrictMath.sinh(-0.000001), 0D);
+        assertEquals("Should return 5.115386441963859", 5.115386441963859,
+                StrictMath.sinh(2.33482), 0D);
+        assertEquals("Should return POSITIVE_INFINITY",
+                Double.POSITIVE_INFINITY, StrictMath.sinh(Double.MAX_VALUE), 0D);
+        assertEquals("Should return 4.9E-324", 4.9E-324, StrictMath
+                .sinh(Double.MIN_VALUE), 0D);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#sqrt(double)
+     */
+    @SmallTest
+    public void testSqrtD() {
+        // Test for method double java.lang.StrictMath.sqrt(double)
+        assertEquals("Incorrect root returned1",
+                2, StrictMath.sqrt(StrictMath.pow(StrictMath.sqrt(2), 4)), 0.0);
+        assertEquals("Incorrect root returned2", 7, StrictMath.sqrt(49), 0.0);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#tan(double)
+     */
+    @SmallTest
+    public void testTanD() {
+        // Test for method double java.lang.StrictMath.tan(double)
+        assertTrue(
+                "Returned incorrect tangent: ",
+                StrictMath.tan(StrictMath.atan(1.0)) <= 1.0
+                        || StrictMath.tan(StrictMath.atan(1.0)) >= 9.9999999999999983E-1);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#tanh(double)
+     */
+    @SmallTest
+    public void testTanhD() {
+        // Test for special situations
+        assertTrue(Double.isNaN(StrictMath.tanh(Double.NaN)));
+        assertEquals("Should return +1.0", +1.0, StrictMath
+                .tanh(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Should return -1.0", -1.0, StrictMath
+                .tanh(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals(Double.doubleToLongBits(0.0), Double
+                .doubleToLongBits(StrictMath.tanh(0.0)));
+        assertEquals(Double.doubleToLongBits(+0.0), Double
+                .doubleToLongBits(StrictMath.tanh(+0.0)));
+        assertEquals(Double.doubleToLongBits(-0.0), Double
+                .doubleToLongBits(StrictMath.tanh(-0.0)));
+
+        assertEquals("Should return 1.0", 1.0, StrictMath.tanh(1234.56), 0D);
+        assertEquals("Should return -1.0", -1.0, StrictMath.tanh(-1234.56), 0D);
+        assertEquals("Should return 9.999999999996666E-7",
+                9.999999999996666E-7, StrictMath.tanh(0.000001), 0D);
+        assertEquals("Should return 0.981422884124941", 0.981422884124941,
+                StrictMath.tanh(2.33482), 0D);
+        assertEquals("Should return 1.0", 1.0, StrictMath
+                .tanh(Double.MAX_VALUE), 0D);
+        assertEquals("Should return 4.9E-324", 4.9E-324, StrictMath
+                .tanh(Double.MIN_VALUE), 0D);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#random()
+     */
+    @MediumTest
+    public void testRandom() {
+        // There isn't a place for these tests so just stick them here
+        assertEquals("Wrong value E",
+                4613303445314885481L, Double.doubleToLongBits(StrictMath.E));
+        assertEquals("Wrong value PI",
+                4614256656552045848L, Double.doubleToLongBits(StrictMath.PI));
+
+        for (int i = 500; i >= 0; i--) {
+            double d = StrictMath.random();
+            assertTrue("Generated number is out of range: " + d, d >= 0.0
+                    && d < 1.0);
+        }
+    }
+
+    /**
+     * @tests java.lang.StrictMath#toRadians(double)
+     */
+    @MediumTest
+    public void testToRadiansD() {
+        for (double d = 500; d >= 0; d -= 1.0) {
+            double converted = StrictMath.toDegrees(StrictMath.toRadians(d));
+            assertTrue("Converted number not equal to original. d = " + d,
+                    converted >= d * 0.99999999 && converted <= d * 1.00000001);
+        }
+    }
+
+    /**
+     * @tests java.lang.StrictMath#toDegrees(double)
+     */
+    @MediumTest
+    public void testToDegreesD() {
+        for (double d = 500; d >= 0; d -= 1.0) {
+            double converted = StrictMath.toRadians(StrictMath.toDegrees(d));
+            assertTrue("Converted number not equal to original. d = " + d,
+                    converted >= d * 0.99999999 && converted <= d * 1.00000001);
+        }
+    }
+
+    /**
+     * @tests java.lang.StrictMath#ulp(double)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testUlp_D() {
+        // Test for special cases
+        assertTrue("Should return NaN", Double
+                .isNaN(StrictMath.ulp(Double.NaN)));
+        assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY,
+                StrictMath.ulp(Double.POSITIVE_INFINITY), 0D);
+        assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY,
+                StrictMath.ulp(Double.NEGATIVE_INFINITY), 0D);
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+                .ulp(0.0), 0D);
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+                .ulp(+0.0), 0D);
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+                .ulp(-0.0), 0D);
+        assertEquals("Returned incorrect value", StrictMath.pow(2, 971),
+                StrictMath.ulp(Double.MAX_VALUE), 0D);
+        assertEquals("Returned incorrect value", StrictMath.pow(2, 971),
+                StrictMath.ulp(-Double.MAX_VALUE), 0D);
+
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+                .ulp(Double.MIN_VALUE), 0D);
+        assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+                .ulp(-Double.MIN_VALUE), 0D);
+
+        assertEquals("Returned incorrect value", 2.220446049250313E-16,
+                StrictMath.ulp(1.0), 0D);
+        assertEquals("Returned incorrect value", 2.220446049250313E-16,
+                StrictMath.ulp(-1.0), 0D);
+        assertEquals("Returned incorrect value", 2.2737367544323206E-13,
+                StrictMath.ulp(1153.0), 0D);
+    }
+
+    /**
+     * @tests java.lang.StrictMath#ulp(float)
+     */
+    @SuppressWarnings("boxing")
+    @SmallTest
+    public void testUlpF() {
+        // Test for special cases
+        assertTrue("Should return NaN", Float.isNaN(StrictMath.ulp(Float.NaN)));
+        assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY,
+                StrictMath.ulp(Float.POSITIVE_INFINITY), 0f);
+        assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY,
+                StrictMath.ulp(Float.NEGATIVE_INFINITY), 0f);
+        assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+                .ulp(0.0f), 0f);
+        assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+                .ulp(+0.0f), 0f);
+        assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+                .ulp(-0.0f), 0f);
+        assertEquals("Returned incorrect value", 2.028241E31f, StrictMath
+                .ulp(Float.MAX_VALUE), 0f);
+        assertEquals("Returned incorrect value", 2.028241E31f, StrictMath
+                .ulp(-Float.MAX_VALUE), 0f);
+
+        assertEquals("Returned incorrect value", 1.4E-45f, StrictMath
+                .ulp(Float.MIN_VALUE), 0f);
+        assertEquals("Returned incorrect value", 1.4E-45f, StrictMath
+                .ulp(-Float.MIN_VALUE), 0f);
+
+        assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath
+                .ulp(1.0f), 0f);
+        assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath
+                .ulp(-1.0f), 0f);
+        assertEquals("Returned incorrect value", 1.2207031E-4f, StrictMath
+                .ulp(1153.0f), 0f);
+        assertEquals("Returned incorrect value", 5.6E-45f, Math
+                .ulp(9.403954E-38f), 0f);
+    }
+}
diff --git a/tests/CoreTests/android/core/StringReaderTest.java b/tests/CoreTests/android/core/StringReaderTest.java
new file mode 100644
index 0000000..66b3e81
--- /dev/null
+++ b/tests/CoreTests/android/core/StringReaderTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class StringReaderTest extends TestCase {
+
+    @SmallTest
+    public void testStringReader() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+
+        StringReader a = new StringReader(str);
+        StringReader b = new StringReader(str);
+        StringReader c = new StringReader(str);
+        StringReader d = new StringReader(str);
+
+        assertEquals(str, IOUtil.read(a));
+        assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+        assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+        assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+    }
+}
diff --git a/tests/CoreTests/android/core/StringTest.java b/tests/CoreTests/android/core/StringTest.java
new file mode 100644
index 0000000..957dd40
--- /dev/null
+++ b/tests/CoreTests/android/core/StringTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import com.ibm.icu4jni.text.RuleBasedNumberFormat;
+import com.ibm.icu4jni.text.RuleBasedNumberFormat.RBNFType;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Some String tests.
+ */
+public class StringTest extends TestCase {
+    private String germanSpelloutRule = "%alt-ones:" +
+            "    -x: minus >>;" +
+            "    x.x: << komma >>;" +
+            "    null; eins; =%%main=;" +
+            "%%main:" +
+            "    null; ein; zwei; drei; vier; f\u00fcnf; sechs; sieben; acht; neun;\n" +
+            "    zehn; elf; zwu00f6lf; >>zehn;" +
+            "    20: [>>und]zwanzig;" +
+            "    30: [>>und]dreiu00dfig;" +
+            "    40: [>>und]vierzig;" +
+            "    50: [>>und]fu00fcnfzig;" +
+            "    60: [>>und]sechzig;" +
+            "    70: [>>und]siebzig;" +
+            "    80: [>>und]achtzig;" +
+            "    90: [>>und]neunzig;" +
+            "    100: hundert[>%alt-ones>];" +
+            "    200: <<hundert[>%alt-ones>];" +
+            "    1000: tausend[>%alt-ones>];" +
+            "    1100: tausendein[>%alt-ones>];" +
+            "    1200: tausend[>%alt-ones>];" +
+            "    2000: <<tausend[>%alt-ones>];";
+
+    @SmallTest
+    public void testString() throws Exception {
+        String test = "0123456789";
+        String test1 = new String("0123456789");    // different object
+        String test2 = new String("0123456780");    // different value
+        String offset = new String("xxx0123456789yyy");
+        String sub = offset.substring(3, 13);
+
+        assertEquals(test, test);
+        assertEquals(test, test1);
+        assertFalse(test.equals(test2));
+
+        assertEquals(0, test.compareTo(test1));
+        assertTrue(test1.compareTo(test2) > 0);
+        assertTrue(test2.compareTo(test1) < 0);
+
+        /* compare string with a nonzero offset, in left/right side */
+        assertEquals(0, test.compareTo(sub));
+        assertEquals(0, sub.compareTo(test));
+        assertEquals(test, sub);
+        assertEquals(sub, test);
+        /* same base, one is a substring */
+        assertFalse(offset.equals(sub));
+        assertFalse(sub.equals(offset));
+        /* wrong class */
+        assertFalse(test.equals(this));
+
+        /* null ptr - throw */
+        try {
+            test.compareTo(null);
+            fail("didn't get expected npe");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+        /* null ptr - ok */
+        assertFalse(test.equals(null));
+
+        test = test.substring(1);
+        assertEquals("123456789", test);
+        assertFalse(test.equals(test1));
+
+        test = test.substring(1);
+        assertEquals("23456789", test);
+
+        test = test.substring(1);
+        assertEquals("3456789", test);
+
+        test = test.substring(1);
+        assertEquals("456789", test);
+
+        test = test.substring(3, 5);
+        assertEquals("78", test);
+
+        test = "this/is/a/path";
+        String[] strings = test.split("/");
+        assertEquals(4, strings.length);
+
+        assertEquals("this is a path", test.replaceAll("/", " "));
+        assertEquals("this is a path", test.replace("/", " "));
+
+        assertEquals(0, "abc".compareToIgnoreCase("ABC"));
+        assertTrue("abc".compareToIgnoreCase("DEF") < 0);
+        assertTrue("ABC".compareToIgnoreCase("def") < 0);
+        assertTrue("Now".compareTo("Mow") > 0);
+        assertTrue("Now".compareToIgnoreCase("Mow") > 0);
+
+        // RuleBasedNumberFormnat tests
+        RuleBasedNumberFormat format = new RuleBasedNumberFormat();
+        format.open(RBNFType.SPELLOUT);
+        String result = format.format(15);
+        assertEquals("Expected spellout format: 'fifteen' but was "
+                + result, "fifteen", result);
+        format.close();
+
+        format.open(RBNFType.DURATION);
+        result = format.format(15);
+        assertEquals("Expected spellout format: '15 sec.' but was "
+                + result, "15 sec.", result);
+        format.close();
+
+        format.open(RBNFType.ORDINAL);
+        result = format.format(15);
+        assertEquals("Expected spellout format: '15th' but was "
+                + result, "15th", result);
+        format.close();
+        format.open(germanSpelloutRule);
+
+        result = format.format(1323);
+        assertEquals("Expected spellout format: 'tausenddrei" +
+                "hundertdreiundzwanzig' but was " + result, "tausend" +
+                        "dreihundertdreiundzwanzig", result);
+            int res = format.parse("tausenddreihundertdreiundzwanzig")
+                    .intValue();
+            assertEquals("Expected spellout format: 'tausend" +
+                    "dreihundertdreiundzwanzig' but was " + res , 1323, res);
+        format.close();
+    }
+}
+
diff --git a/tests/CoreTests/android/core/StringWriterTest.java b/tests/CoreTests/android/core/StringWriterTest.java
new file mode 100644
index 0000000..fed2221
--- /dev/null
+++ b/tests/CoreTests/android/core/StringWriterTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.StringWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class StringWriterTest extends TestCase {
+
+    @SmallTest
+    public void testStringWriter() throws Exception {
+        String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+        StringWriter a = new StringWriter(10);
+
+        a.write(str, 0, 26);
+        a.write('X');
+
+        assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString());
+
+        a.write("alphabravodelta", 5, 5);
+        a.append('X');
+        assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", a.toString());
+        a.append("omega");
+        assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", a.toString());
+    }
+}
diff --git a/tests/CoreTests/android/core/TestEventHandler.java b/tests/CoreTests/android/core/TestEventHandler.java
new file mode 100644
index 0000000..4cfcade
--- /dev/null
+++ b/tests/CoreTests/android/core/TestEventHandler.java
@@ -0,0 +1,811 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.apache.http.protocol.HTTP;
+import android.util.Log;
+import android.util.Config;
+import android.net.http.*;
+
+/**
+ * Implements EventHandler and provides test functionality to validate
+ * responses to requests from the test server
+ */
+public class TestEventHandler implements EventHandler {
+
+    /**
+     * Status variables
+     */
+    private int majorVersion = -1;
+    private int minorVersion = -1;
+    private int responseCode = -1;
+    private String reasonPhrase;
+
+    /* List of headers received */
+    private Map<String, String> headerMap;
+
+    /* Used to sync low level delayed requests */
+    public static final Object syncObj = new Object();
+
+    /* Indicates whether the low level request testing is in operation */
+    private boolean useLowLevel = false;
+
+    /* Indicates whether responses should be automatically generated or
+     * delayed
+     */
+    private boolean delayResponse = false;
+
+    /* Test method expectation identifiers */
+    public final static int TEST_REQUEST_SENT = 0;
+    public final static int TEST_STATUS = 1;
+    public final static int TEST_HEADERS = 2;
+    public final static int TEST_LOCATION_CHANGED = 3;
+    public final static int TEST_DATA = 4;
+    public final static int TEST_ENDDATA = 5;
+    public final static int TEST_ERROR = 6;
+    public final static int TEST_SSL_CERTIFICATE_ERROR = 7;
+
+    public final static int TEST_NUM_EXPECTS = 8;
+
+    /* Expected status codes */
+    private int expectMajor = -1;
+    private int expectMinor = -1;
+    private int expectCode = -1;
+
+    /* Array indicating which event types are expected */
+    private boolean[] expects = new boolean[TEST_NUM_EXPECTS];
+
+    /* Array indicating which event types are not expected */
+    private boolean[] notExpecting = new boolean[TEST_NUM_EXPECTS];
+
+    /* Indicates which events have been received */
+    private boolean[] eventsReceived = new boolean[TEST_NUM_EXPECTS];
+
+    /* Redirection variables */
+    private String expectLocation;
+    private int expectPermanent = -1;
+
+    /* Content data expected to be received */
+    private byte[] expectData;
+    private int expectDataLength = -1;
+
+    private int expectErrorId = -1;
+
+    private int expectSslErrors = -1;
+    private SslCertificate expectCertificate;
+
+    public class TestHeader {
+        public TestHeader(String n, String v) {
+            name = n;
+            value = v;
+        }
+        public String name;
+        public String value;
+    }
+    
+    private ArrayList<TestHeader> expectHeaders = new ArrayList<TestHeader>();
+
+    /* Holds failure details */
+    private StringBuffer expectDetails = new StringBuffer();
+
+    /* If we use a request handle, we retain a reference here for redirects
+     * using setupRedirect
+     */
+    private RequestHandle mRequestHandle;
+
+    /* The low level API uses this reference also for non-delayed requests */
+    private LowLevelNetRunner netRunner;
+
+    public TestEventHandler() {
+        for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
+            expects[i] = false;
+            notExpecting[i] = false;
+            eventsReceived[i] = false;
+        }
+    }
+
+    /**
+     * Implementation of EventHandler method called when a request has been
+     * sent. If the test is waiting for this call, it will be signalled,
+     * otherwise this method will trigger the response to be read
+     * automatically.
+     */
+    public void requestSent() {
+      Log.v(LOGTAG, "TestEventHandler:requestSent()");
+      expects[TEST_REQUEST_SENT] = false;
+      eventsReceived[TEST_REQUEST_SENT] = true;
+      if (notExpecting[TEST_REQUEST_SENT]) {
+          expectDetails.append("Request sent event received but not expected");
+          expectDetails.append("\r\n");
+      }
+
+      if (useLowLevel) {
+        if (delayResponse) {
+          synchronized (syncObj) {
+            syncObj.notifyAll();
+          }
+        } else {
+            // mRequest.startReadingResponse();
+        }
+      }
+    }
+
+    /**
+     * Implements the EventHandler status method called when a server status
+     * response is received.
+     * @param major_version The HTTP major version
+     * @param minor_version The HTTP minor version
+     * @param code The status code
+     * @param reason_phrase A reason phrase passed to us by the server
+     */
+    public void status(int major_version, int minor_version,
+        int code, String reason_phrase) {
+      if (Config.LOGV) {
+        Log.v(LOGTAG, "TestEventHandler:status() major: " + major_version +
+            " minor: " + minor_version +
+            " code: " + code +
+            " reason: " + reason_phrase);
+      }
+
+      eventsReceived[TEST_STATUS] = true;
+      if (notExpecting[TEST_STATUS]) {
+        expectDetails.append("Status event received but not expected");
+        expectDetails.append("\r\n");
+      }
+
+      majorVersion = major_version;
+      minorVersion = minor_version;
+      responseCode = code;
+      reasonPhrase = reason_phrase;
+
+      if (expectMajor != -1) {
+        if (expectMajor == major_version) {
+          expectMajor = -1;
+        } else {
+          expectDetails.append("Major version expected:"+expectMajor+
+              " got:"+major_version);
+          expectDetails.append("\r\n");
+        }
+      }
+
+      if (expectMinor != -1) {
+        if (expectMinor == minor_version) {
+          expectMinor = -1;
+        } else {
+          expectDetails.append("Minor version expected:"+expectMinor+
+              " got:"+minor_version);
+          expectDetails.append("\r\n");
+        }
+      }
+
+      if (expectCode != -1) {
+        if (expectCode == code) {
+          expectCode = -1;
+        } else {
+          expectDetails.append("Status code expected:"+expectCode+
+              " got:"+code);
+          expectDetails.append("\r\n");
+        }
+      }
+
+
+      if ((expectMajor == -1) && (expectMinor == -1) && (expectCode == -1)) {
+        expects[TEST_STATUS] = false;
+      } else {
+        System.out.println("MAJOR = "+expectMajor+" MINOR = "+expectMinor+
+            " CODE = "+expectCode);
+      }
+    }
+
+    /**
+     * Implements the EventHandler headers method called when a server
+     * sends header fields
+     */
+    public void headers(Headers headers) {
+        if (Config.LOGV) {
+            Log.v(LOGTAG, "TestEventHandler:headers()");
+        }
+        expects[TEST_HEADERS] = false;
+
+        if (notExpecting[TEST_HEADERS]) {
+            expectDetails.append("Header event received but not expected");
+            expectDetails.append("\r\n");
+        }
+
+        /* Check through headers received for matches with expected
+         * headers */
+        if (expectHeaders.isEmpty()) {
+            return;
+        }      
+        
+        for (int i = expectHeaders.size() - 1; i >= 0; i--) {
+            TestHeader h =  expectHeaders.get(i);
+            System.out.println("Expected header name: " + h.name);
+            String s = null;
+            switch (h.name.hashCode()) {
+            case -1132779846:
+                s = Long.toString(headers.getContentLength());
+                break;
+            case 785670158:
+                s = headers.getContentType();
+                break;
+            case 2095084583:
+                s = headers.getContentEncoding();
+                break;
+            case 1901043637:
+                s = headers.getLocation();
+                break;
+            case -243037365:
+                s = headers.getWwwAuthenticate();
+                break;
+            case -301767724:
+                s = headers.getProxyAuthenticate();
+                break;
+            case -1267267485:
+                s = headers.getContentDisposition();
+                break;
+            case 1397189435:
+                s = headers.getAcceptRanges();
+                break;
+            case -1309235404:
+                s = headers.getExpires();
+                break;
+            case -208775662:
+                s = headers.getCacheControl();
+                break;
+            case 150043680:
+                s = headers.getLastModified();
+                break;
+            case 3123477:
+                s = headers.getEtag();
+                break;
+            case -775651618:
+                int ct = headers.getConnectionType();
+                if (ct == Headers.CONN_CLOSE) {
+                    s = HTTP.CONN_CLOSE;
+                } else if (ct == Headers.CONN_KEEP_ALIVE) {
+                    s = HTTP.CONN_KEEP_ALIVE;
+                }
+                break;
+            default:
+                s = null;
+                
+            }
+            if (evaluateHeader(h, s)) {
+                expectHeaders.remove(i);
+            }
+        }
+            
+    }
+
+    public boolean evaluateHeader(TestHeader h, String value) {
+        if (value == null) {
+            expects[TEST_HEADERS] = true;
+            System.out.print(" Missing!  ");
+            expectDetails.append(" missing header " + h.name);
+            return false;
+        }
+        if (h.value == null) {
+            System.out.println("Expect value = null");
+            return true;
+        }
+        System.out.println("Expect value = " +
+                (h.value.toLowerCase()) + " got " +
+                value.toLowerCase());
+        
+        if (!h.value.equalsIgnoreCase(value)) {
+            expectDetails.append("expect header value " + h.value +
+                    " got " + value);
+            expects[TEST_HEADERS] = true;
+            return false;
+        }
+        return true;
+    }
+    /**
+     * Implements the EventHandler locationChanged method called when a server
+     * sends a redirect message
+     * @param newLocation The URL to the new server
+     * @param permanent Indicator of whether this is a permanent change
+     */
+    public void locationChanged(String newLocation, boolean permanent) {
+      if (Config.LOGV) {
+        Log.v(LOGTAG, "TestEventHandler: locationChanged() " +
+            newLocation + " permanent " + permanent);
+      }
+
+      eventsReceived[TEST_LOCATION_CHANGED] = true;
+      if (notExpecting[TEST_LOCATION_CHANGED]) {
+        expectDetails.append("Location changed event received but "+
+            "not expected");
+        expectDetails.append("\r\n");
+      }
+
+      if (expectLocation != null) {
+        if (expectLocation.equals(newLocation)) {
+          expectLocation = null;
+        } else {
+          expectDetails.append("Location expected:"+expectLocation+
+              " got:"+newLocation);
+          expectDetails.append("\r\n");
+        }
+      }
+
+      if (expectPermanent != -1) {
+        if (((expectPermanent == 0) && !permanent) ||
+            ((expectPermanent == 1) && permanent)){
+          expectPermanent = -1;
+        } else {
+          expectDetails.append("Location permanent expected:"+
+              expectPermanent+" got"+permanent);
+          expectDetails.append("\r\n");
+        }
+      }
+
+      if ((expectLocation == null) && (expectPermanent == -1))
+        expects[TEST_LOCATION_CHANGED] = false;
+    }
+
+    /**
+     * Implements the EventHandler data method called when a server
+     * sends content data
+     * @param data The byte array content
+     * @param len The length of the data
+     */
+    public void data(byte[] data, int len) {
+      boolean mismatch = false;
+
+      if (Config.LOGV) {
+        Log.v(LOGTAG, "TestEventHandler: data() " + len + " bytes");
+      }
+
+      eventsReceived[TEST_DATA] = true;
+      if (notExpecting[TEST_DATA]) {
+        expectDetails.append("Data event received but not expected");
+        expectDetails.append("\r\n");
+      }
+
+      Log.v(LOGTAG, new String(data, 0, len));
+
+      if (expectDataLength != -1) {
+        if (expectDataLength == len) {
+          expectDataLength = -1;
+        } else {
+          expectDetails.append("expect data length mismatch expected:"+
+              expectDataLength+" got:"+len);
+          expectDetails.append("\r\n");
+        }
+
+        /* Check data only if length is the same */
+        if ((expectDataLength == -1) && expectData != null) {
+          for (int i = 0; i < len; i++) {
+            if (expectData[i] != data[i]) {
+              mismatch = true;
+              expectDetails.append("Expect data mismatch at byte "+
+                  i+" expected:"+expectData[i]+" got:"+data[i]);
+              expectDetails.append("\r\n");
+              break;
+            }
+          }
+        }
+      }
+
+      if ((expectDataLength == -1) || !mismatch)
+        expects[TEST_DATA] = false;
+    }
+
+    /**
+     * Implements the EventHandler endData method called to
+     * indicate completion or a request
+     */
+    public void endData() {
+      if (Config.LOGV) {
+        Log.v(LOGTAG, "TestEventHandler: endData() called");
+      }
+
+      eventsReceived[TEST_ENDDATA] = true;
+      if (notExpecting[TEST_ENDDATA]) {
+        expectDetails.append("End data event received but not expected");
+        expectDetails.append("\r\n");
+      }
+
+      expects[TEST_ENDDATA] = false;
+
+      if (useLowLevel) {
+        if (delayResponse) {
+          synchronized (syncObj) {
+            syncObj.notifyAll();
+          }
+        } else {
+          if (netRunner != null) {
+            System.out.println("TestEventHandler: endData() stopping "+
+                netRunner);
+            netRunner.decrementRunCount();
+          }
+        }
+      }
+    }
+
+    /**
+     * Implements the EventHandler certificate method called every
+     * time a resource is loaded via a secure connection
+     */
+    public void certificate(SslCertificate certificate) {}
+
+    /**
+     * Implements the EventHandler error method called when a server
+     * sends header fields
+     * @param id Status code of the error
+     * @param description Brief description of the error
+     */
+    public void error(int id, String description) {
+      if (Config.LOGV) {
+        Log.v(LOGTAG, "TestEventHandler: error() called Id:" + id +
+            " description " + description);
+      }
+
+      eventsReceived[TEST_ERROR] = true;
+      if (notExpecting[TEST_ERROR]) {
+        expectDetails.append("Error event received but not expected");
+        expectDetails.append("\r\n");
+      }
+      if (expectErrorId != -1) {
+        if (expectErrorId == id) {
+          expectErrorId = -1;
+        } else {
+          expectDetails.append("Error Id expected:"+expectErrorId+
+              " got:"+id);
+          expectDetails.append("\r\n");
+        }
+      }
+
+      if (expectErrorId == -1)
+        expects[TEST_ERROR] = false;
+
+      if (useLowLevel) {
+        if (delayResponse) {
+          synchronized (syncObj) {
+            syncObj.notifyAll();
+          }
+        } else {
+          if (netRunner != null) {
+            System.out.println("TestEventHandler: endData() stopping "+
+                netRunner);
+            netRunner.decrementRunCount();
+          }
+        }
+      }
+    }
+
+    /**
+     * SSL certificate error callback. Handles SSL error(s) on the way
+     * up to the user.
+     */
+    public void handleSslErrorRequest(SslError error) {
+      int primaryError = error.getPrimaryError();
+
+      if (Config.LOGV) {
+        Log.v(LOGTAG, "TestEventHandler: handleSslErrorRequest(): "+
+              " primary error:" + primaryError +
+              " certificate: " + error.getCertificate());
+      }
+
+      eventsReceived[TEST_SSL_CERTIFICATE_ERROR] = true;
+      if (notExpecting[TEST_SSL_CERTIFICATE_ERROR]) {
+        expectDetails.append("SSL Certificate error event received "+
+            "but not expected");
+        expectDetails.append("\r\n");
+      }
+
+      if (expectSslErrors != -1) {
+        if (expectSslErrors == primaryError) {
+            expectSslErrors = -1;
+        } else {
+            expectDetails.append("SslCertificateError id expected:"+
+                expectSslErrors+" got: " + primaryError);
+            expectDetails.append("\r\n");
+        }
+      }
+
+      // SslCertificate match here?
+
+      if (expectSslErrors == -1) // && expectSslCertificate == certificate?
+        expects[TEST_SSL_CERTIFICATE_ERROR] = false;
+    }
+
+    /**
+     * Use the low level net runner with no delayed response
+     * @param runner The LowLevelNetRunner object
+     */
+    public void setNetRunner(LowLevelNetRunner runner) {
+      setNetRunner(runner, false);
+    }
+
+    /**
+     * Use the low level net runner and specify if the response
+     * should be delayed
+     * @param runner The LowLevelNetRunner object
+     * @param delayedResponse Set to true is you will use the
+     * waitForRequestSent/waitForRequestResponse routines
+     */
+    public void setNetRunner(LowLevelNetRunner runner,
+        boolean delayedResponse) {
+      netRunner = runner;
+      useLowLevel = true;
+      delayResponse = delayedResponse;
+
+      if (!delayResponse)
+        netRunner.incrementRunCount();
+    }
+
+    /**
+     * Enable this listeners Request object to read server responses.
+     * This should only be used in conjunction with setDelayResponse(true)
+     */
+    public void waitForRequestResponse() {
+      if (!delayResponse || !useLowLevel) {
+        Log.d(LOGTAG, " Cant do this without delayReponse set ");
+        return;
+      }
+
+      //if (mRequest != null) {
+          // mRequest.startReadingResponse();
+      // }
+      /* Now wait for the response to be completed either through endData
+       * or an error
+       */
+      synchronized (syncObj) {
+        try {
+          syncObj.wait();
+        } catch (InterruptedException e) {
+        }
+      }
+    }
+
+    /**
+     * Enable this listeners Request object to read server responses.
+     * This should only be used in conjunction with setDelayResponse(true)
+     */
+    public void waitForRequestSent() {
+      if (!delayResponse || !useLowLevel) {
+        Log.d(LOGTAG, " Cant do this without delayReponse set ");
+        return;
+      }
+
+      /* Now wait for the response to be completed either through endData
+       * or an error
+       */
+      synchronized (syncObj) {
+        try {
+          syncObj.wait();
+        } catch (InterruptedException e) {
+        }
+      }
+    }
+
+    /* Test expected values - these routines set the tests expectations */
+
+    public void expectRequestSent() {
+        expects[TEST_REQUEST_SENT] = true;
+    }
+
+    public void expectNoRequestSent() {
+        notExpecting[TEST_REQUEST_SENT] = true;
+    }
+
+    public void expectStatus() {
+        expects[TEST_STATUS] = true;
+    }
+
+    public void expectNoStatus() {
+        notExpecting[TEST_STATUS] = true;
+    }
+
+    public void expectStatus(int major, int minor, int code) {
+        expects[TEST_STATUS] = true;
+        expectMajor = major;
+        expectMinor = minor;
+        expectCode = code;
+    }
+
+    public void expectStatus(int code) {
+        expects[TEST_STATUS] = true;
+        expectCode = code;
+    }
+
+    public void expectHeaders() {
+        expects[TEST_HEADERS] = true;
+    }
+
+    public void expectNoHeaders() {
+        notExpecting[TEST_HEADERS] = true;
+    }
+
+    public void expectHeaderAdd(String name) {
+        expects[TEST_HEADERS] = true;
+        TestHeader h = new TestHeader(name.toLowerCase(), null);
+        expectHeaders.add(h);
+    }
+
+    public void expectHeaderAdd(String name, String value) {
+        expects[TEST_HEADERS] = true;
+        TestHeader h = new TestHeader(name.toLowerCase(), value);
+        expectHeaders.add(h);
+    }
+
+    public void expectLocationChanged() {
+        expects[TEST_LOCATION_CHANGED] = true;
+    }
+
+    public void expectNoLocationChanged() {
+            notExpecting[TEST_LOCATION_CHANGED] = true;
+    }
+
+    public void expectLocationChanged(String newLocation) {
+        expects[TEST_LOCATION_CHANGED] = true;
+        expectLocation = newLocation;
+    }
+
+    public void expectLocationChanged(String newLocation, boolean permanent) {
+        expects[TEST_LOCATION_CHANGED] = true;
+        expectLocation = newLocation;
+        expectPermanent = permanent ? 1 : 0;
+    }
+
+    public void expectData() {
+        expects[TEST_DATA] = true;
+    }
+
+    public void expectNoData() {
+        notExpecting[TEST_DATA] = true;
+    }
+
+    public void expectData(int len) {
+        expects[TEST_DATA] = true;
+        expectDataLength = len;
+    }
+
+    public void expectData(byte[] data, int len) {
+        expects[TEST_DATA] = true;
+        expectData = new byte[len];
+        expectDataLength = len;
+
+        for (int i = 0; i < len; i++) {
+            expectData[i] = data[i];
+        }
+    }
+
+    public void expectEndData() {
+        expects[TEST_ENDDATA] = true;
+    }
+
+    public void expectNoEndData() {
+            notExpecting[TEST_ENDDATA] = true;
+    }
+
+    public void expectError() {
+        expects[TEST_ERROR] = true;
+    }
+
+    public void expectNoError() {
+        notExpecting[TEST_ERROR] = true;
+    }
+
+    public void expectError(int errorId) {
+        expects[TEST_ERROR] = true;
+        expectErrorId = errorId;
+    }
+
+    public void expectSSLCertificateError() {
+        expects[TEST_SSL_CERTIFICATE_ERROR] = true;
+    }
+
+    public void expectNoSSLCertificateError() {
+            notExpecting[TEST_SSL_CERTIFICATE_ERROR] = true;
+    }
+
+    public void expectSSLCertificateError(int errors) {
+        expects[TEST_SSL_CERTIFICATE_ERROR] = true;
+        expectSslErrors = errors;
+    }
+
+    public void expectSSLCertificateError(SslCertificate certificate) {
+        expects[TEST_SSL_CERTIFICATE_ERROR] = true;
+        expectCertificate = certificate;
+    }
+
+    /**
+     * Test to see if current expectations match recieved information
+     * @return True is all expected results have been matched
+     */
+    public boolean expectPassed() {
+        for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
+            if (expects[i] == true) {
+                return false;
+            }
+        }
+
+        for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
+            if (eventsReceived[i] && notExpecting[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Return message indicating expectation failures
+     */
+    public String getFailureMessage() {
+        return expectDetails.toString();
+    }
+
+    /**
+     * Reset all expectation values for re-use
+     */
+    public void resetExpects() {
+        expectMajor = -1;
+        expectMinor = -1;
+        expectCode = -1;
+        expectLocation = null;
+        expectPermanent = -1;
+        expectErrorId = -1;
+        expectSslErrors = -1;
+        expectCertificate = null;
+        expectDetails.setLength(0);
+        expectHeaders.clear();
+
+        for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
+            expects[i] = false;
+            notExpecting[i] = false;
+            eventsReceived[i] = false;
+        }
+
+        for (int i = 0; i < expectDataLength; i++) {
+            expectData[i] = 0;
+        }
+
+        expectDataLength = -1;
+    }
+
+    /**
+     * Attach the RequestHandle to this handler
+     * @param requestHandle The RequestHandle
+     */
+    public void attachRequestHandle(RequestHandle requestHandle) {
+        if (Config.LOGV) {
+            Log.v(LOGTAG, "TestEventHandler.attachRequestHandle(): " +
+                    "requestHandle: " +  requestHandle);
+        }
+        mRequestHandle = requestHandle;
+    }
+
+    /**
+     * Detach the RequestHandle
+     */
+    public void detachRequestHandle() {
+        if (Config.LOGV) {
+            Log.v(LOGTAG, "TestEventHandler.detachRequestHandle(): " +
+                    "requestHandle: " + mRequestHandle);
+        }
+        mRequestHandle = null;
+    }
+
+    protected final static String LOGTAG = "http";
+}
diff --git a/tests/CoreTests/android/core/TestWebData.java b/tests/CoreTests/android/core/TestWebData.java
new file mode 100644
index 0000000..2ef19be
--- /dev/null
+++ b/tests/CoreTests/android/core/TestWebData.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+/**
+ * Represents test data used by the Request API tests
+ */
+public class TestWebData {
+
+  /*
+   * Simple Html body
+   * <html>
+   * <body>
+   * <h1>Hello World!</h1>
+   * </body>
+   * </html>
+   */
+  public final static byte[] test1 = {
+    (byte)0x3c, (byte)0x68, (byte)0x74, (byte)0x6d,
+    (byte)0x6c, (byte)0x3e, (byte)0x0a, (byte)0x3c,
+    (byte)0x62, (byte)0x6f, (byte)0x64, (byte)0x79,
+    (byte)0x3e, (byte)0x0a, (byte)0x3c, (byte)0x68,
+    (byte)0x31, (byte)0x3e, (byte)0x48, (byte)0x65,
+    (byte)0x6c, (byte)0x6c, (byte)0x6f, (byte)0x20,
+    (byte)0x57, (byte)0x6f, (byte)0x72, (byte)0x6c,
+    (byte)0x64, (byte)0x21, (byte)0x3c, (byte)0x2f,
+    (byte)0x68, (byte)0x31, (byte)0x3e, (byte)0x0a,
+    (byte)0x3c, (byte)0x2f, (byte)0x62, (byte)0x6f,
+    (byte)0x64, (byte)0x79, (byte)0x3e, (byte)0x0a,
+    (byte)0x3c, (byte)0x2f, (byte)0x68, (byte)0x74,
+    (byte)0x6d, (byte)0x6c, (byte)0x3e, (byte)0x0a
+  };
+
+  /*
+   * Simple Html body
+   * <html>
+   * <body>
+   * <h1>Hello World!</h1>
+   * </body>
+   * </html>
+   */
+  public final static byte[] test2 = {
+    (byte)0x3c, (byte)0x68, (byte)0x74, (byte)0x6d,
+    (byte)0x6c, (byte)0x3e, (byte)0x0a, (byte)0x3c,
+    (byte)0x62, (byte)0x6f, (byte)0x64, (byte)0x79,
+    (byte)0x3e, (byte)0x0a, (byte)0x3c, (byte)0x68,
+    (byte)0x31, (byte)0x3e, (byte)0x48, (byte)0x65,
+    (byte)0x6c, (byte)0x6c, (byte)0x6f, (byte)0x20,
+    (byte)0x57, (byte)0x6f, (byte)0x72, (byte)0x6c,
+    (byte)0x64, (byte)0x21, (byte)0x3c, (byte)0x2f,
+    (byte)0x68, (byte)0x31, (byte)0x3e, (byte)0x0a,
+    (byte)0x3c, (byte)0x2f, (byte)0x62, (byte)0x6f,
+    (byte)0x64, (byte)0x79, (byte)0x3e, (byte)0x0a,
+    (byte)0x3c, (byte)0x2f, (byte)0x68, (byte)0x74,
+    (byte)0x6d, (byte)0x6c, (byte)0x3e, (byte)0x0a
+  };
+
+  // string for test request post body
+  public final static String postContent = "user=111";
+  
+  // Array of all test data
+  public final static byte[][] tests = {
+    test1,
+    test2
+  };
+
+  /**
+   * List of static test cases for use with test server
+   */
+  public static TestWebData[] testParams = {
+    new TestWebData(52, 14000000, "test1", "text/html", false),
+    new TestWebData(52, 14000002, "test2", "unknown/unknown", false)
+  };
+
+  /**
+   * List of response strings for use by the test server
+   */
+  public static String[] testServerResponse = {
+    "Redirecting 301",
+    "Redirecting 302",
+    "Redirecting 303",
+    "Redirecting 307"
+  };
+
+  // Redirection indices into testServerResponse
+  public final static int REDIRECT_301 = 0;
+  public final static int REDIRECT_302 = 1;
+  public final static int REDIRECT_303 = 2;
+  public final static int REDIRECT_307 = 3;
+
+  /**
+   * Creates a data package with information used by the server when responding
+   * to requests
+   */
+  TestWebData(int length, int lastModified, String name, String type, boolean isDir) {
+    testLength = length;
+    testLastModified = lastModified;
+    testName = name;
+    testType = type;
+    testDir = isDir;
+  }
+
+  // Length of test entity body
+  public int testLength;
+
+  // Last modified date value (milliseconds)
+  public int testLastModified;
+
+  // Test identification name
+  public String testName;
+
+  // The MIME type to assume for this test
+  public String testType;
+
+  // Indicates if this is a directory or not
+  public boolean testDir;
+
+}
diff --git a/tests/CoreTests/android/core/TestWebServer.java b/tests/CoreTests/android/core/TestWebServer.java
new file mode 100644
index 0000000..f73e6ff
--- /dev/null
+++ b/tests/CoreTests/android/core/TestWebServer.java
@@ -0,0 +1,871 @@
+/*
+ * Copyright (C) 2007 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.core;
+
+import android.util.Log;
+
+import java.io.*;
+import java.lang.Thread;
+import java.net.*;
+import java.util.*;
+
+/**
+ * TestWebServer is a simulated controllable test server that
+ * can respond to requests from HTTP clients.
+ *
+ * The server can be controlled to change how it reacts to any
+ * requests, and can be told to simulate various events (such as
+ * network failure) that would happen in a real environment.
+ */
+class TestWebServer implements HttpConstants {
+
+    /* static class data/methods */
+
+    /* The ANDROID_LOG_TAG */
+    private final static String LOGTAG = "httpsv";
+
+    /* Where worker threads stand idle */
+    Vector threads = new Vector();
+
+    /* List of all active worker threads */
+    Vector activeThreads = new Vector();
+
+    /* timeout on client connections */
+    int timeout = 0;
+
+    /* max # worker threads */
+    int workers = 5;
+
+    /* Default port for this server to listen on */
+    final static int DEFAULT_PORT = 8080;
+
+    /* Default socket timeout value */
+    final static int DEFAULT_TIMEOUT = 5000;
+
+    /* Version string (configurable) */
+    protected String HTTP_VERSION_STRING = "HTTP/1.1";
+
+    /* Indicator for whether this server is configured as a HTTP/1.1
+     * or HTTP/1.0 server
+     */
+    private boolean http11 = true;
+
+    /* The thread handling new requests from clients */
+    private AcceptThread acceptT;
+
+    /* timeout on client connections */
+    int mTimeout;
+
+    /* Server port */
+    int mPort;
+
+    /* Switch on/off logging */
+    boolean mLog = false;
+
+    /* If set, this will keep connections alive after a request has been
+     * processed.
+     */
+    boolean keepAlive = true;
+
+    /* If set, this will cause response data to be sent in 'chunked' format */
+    boolean chunked = false;
+
+    /* If set, this will indicate a new redirection host */
+    String redirectHost = null;
+
+    /* If set, this indicates the reason for redirection */
+    int redirectCode = -1;
+
+    /* Set the number of connections the server will accept before shutdown */
+    int acceptLimit = 100;
+
+    /* Count of number of accepted connections */
+    int acceptedConnections = 0;
+
+    public TestWebServer() {
+    }
+
+    /**
+     * Initialize a new server with default port and timeout.
+     * @param log Set true if you want trace output
+     */
+    public void initServer(boolean log) throws Exception {
+        initServer(DEFAULT_PORT, DEFAULT_TIMEOUT, log);
+    }
+
+    /**
+     * Initialize a new server with default timeout.
+     * @param port Sets the server to listen on this port
+     * @param log Set true if you want trace output
+     */
+    public void initServer(int port, boolean log) throws Exception {
+        initServer(port, DEFAULT_TIMEOUT, log);
+    }
+
+    /**
+     * Initialize a new server with default port and timeout.
+     * @param port Sets the server to listen on this port
+     * @param timeout Indicates the period of time to wait until a socket is
+     *                closed
+     * @param log Set true if you want trace output
+     */
+    public void initServer(int port, int timeout, boolean log) throws Exception {
+        mPort = port;
+        mTimeout = timeout;
+        mLog = log;
+        keepAlive = true;
+
+        if (acceptT == null) {
+            acceptT = new AcceptThread();
+            acceptT.init();
+            acceptT.start();
+        }
+    }
+
+    /**
+     * Print to the log file (if logging enabled)
+     * @param s String to send to the log
+     */
+    protected void log(String s) {
+        if (mLog) {
+            Log.d(LOGTAG, s);
+        }
+    }
+
+    /**
+     * Set the server to be an HTTP/1.0 or HTTP/1.1 server.
+     * This should be called prior to any requests being sent
+     * to the server.
+     * @param set True for the server to be HTTP/1.1, false for HTTP/1.0
+     */
+    public void setHttpVersion11(boolean set) {
+        http11 = set;
+        if (set) {
+            HTTP_VERSION_STRING = "HTTP/1.1";
+        } else {
+            HTTP_VERSION_STRING = "HTTP/1.0";
+        }
+    }
+
+    /**
+     * Call this to determine whether server connection should remain open
+     * @param value Set true to keep connections open after a request
+     *              completes
+     */
+    public void setKeepAlive(boolean value) {
+        keepAlive = value;
+    }
+
+    /**
+     * Call this to indicate whether chunked data should be used
+     * @param value Set true to make server respond with chunk encoded
+     *              content data.
+     */
+    public void setChunked(boolean value) {
+        chunked = value;
+    }
+
+    /**
+     * Call this to specify the maximum number of sockets to accept
+     * @param limit The number of sockets to accept
+     */
+    public void setAcceptLimit(int limit) {
+        acceptLimit = limit;
+    }
+
+    /**
+     * Call this to indicate redirection port requirement.
+     * When this value is set, the server will respond to a request with
+     * a redirect code with the Location response header set to the value
+     * specified.
+     * @param redirect The location to be redirected to
+     * @param redirectCode The code to send when redirecting
+     */
+    public void setRedirect(String redirect, int code) {
+        redirectHost = redirect;
+        redirectCode = code;
+        log("Server will redirect output to "+redirect+" code "+code);
+    }
+
+    /**
+     * Cause the thread accepting connections on the server socket to close
+     */
+    public void close() {
+        /* Stop the Accept thread */
+        if (acceptT != null) {
+            log("Closing AcceptThread"+acceptT);
+            acceptT.close();
+            acceptT = null;
+        }
+    }
+    /**
+     * The AcceptThread is responsible for initiating worker threads
+     * to handle incoming requests from clients.
+     */
+    class AcceptThread extends Thread {
+
+        ServerSocket ss = null;
+        boolean running = false;
+
+        public void init() {
+            // Networking code doesn't support ServerSocket(port) yet
+            InetSocketAddress ia = new InetSocketAddress(mPort);
+            while (true) {
+                try {
+                    ss = new ServerSocket();
+                    // Socket timeout functionality is not available yet
+                    //ss.setSoTimeout(5000);
+                    ss.setReuseAddress(true);
+                    ss.bind(ia);
+                    break;
+                } catch (IOException e) {
+                    log("IOException in AcceptThread.init()");                    
+                    e.printStackTrace();
+                    // wait and retry
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e1) {
+                        // TODO Auto-generated catch block
+                        e1.printStackTrace();
+                    }
+                }
+            }
+        }
+
+        /**
+         * Main thread responding to new connections
+         */
+        public synchronized void run() {
+            running = true;
+            try {
+                while (running) {
+                    // Log.d(LOGTAG, "TestWebServer run() calling accept()");
+                    Socket s = ss.accept();
+                    acceptedConnections++;
+                    if (acceptedConnections >= acceptLimit) {
+                        running = false;
+                    }
+
+                    Worker w = null;
+                    synchronized (threads) {
+                        if (threads.isEmpty()) {
+                            Worker ws = new Worker();
+                            ws.setSocket(s);
+                            activeThreads.addElement(ws);
+                            (new Thread(ws, "additional worker")).start();
+                        } else {
+                            w = (Worker) threads.elementAt(0);
+                            threads.removeElementAt(0);
+                            w.setSocket(s);
+                        }
+                    }
+                }
+            } catch (SocketException e) {
+                log("SocketException in AcceptThread: probably closed during accept");
+                running = false;
+            } catch (IOException e) {
+                log("IOException in AcceptThread");
+                e.printStackTrace();
+                running = false;
+            }
+            log("AcceptThread terminated" + this);
+        }
+
+        // Close this socket
+        public void close() {
+            try {
+                running = false;
+                /* Stop server socket from processing further. Currently
+                   this does not cause the SocketException from ss.accept
+                   therefore the acceptLimit functionality has been added
+                   to circumvent this limitation */
+                ss.close();
+
+                // Stop worker threads from continuing
+                for (Enumeration e = activeThreads.elements(); e.hasMoreElements();) {
+                    Worker w = (Worker)e.nextElement();
+                    w.close();
+                }
+                activeThreads.clear();
+
+            } catch (IOException e) {
+                /* We are shutting down the server, so we expect
+                 * things to die. Don't propagate.
+                 */
+                log("IOException caught by server socket close");
+            }
+        }
+    }
+
+    // Size of buffer for reading from the connection
+    final static int BUF_SIZE = 2048;
+
+    /* End of line byte sequence */
+    static final byte[] EOL = {(byte)'\r', (byte)'\n' };
+
+    /**
+     * The worker thread handles all interactions with a current open
+     * connection. If pipelining is turned on, this will allow this
+     * thread to continuously operate on numerous requests before the
+     * connection is closed.
+     */
+    class Worker implements HttpConstants, Runnable {
+
+        /* buffer to use to hold request data */
+        byte[] buf;
+
+        /* Socket to client we're handling */
+        private Socket s;
+
+        /* Reference to current request method ID */
+        private int requestMethod;
+
+        /* Reference to current requests test file/data */
+        private String testID;
+
+        /* Reference to test number from testID */
+        private int testNum;
+
+        /* Reference to whether new request has been initiated yet */
+        private boolean readStarted;
+
+        /* Indicates whether current request has any data content */
+        private boolean hasContent = false;
+
+        boolean running = false;
+
+        /* Request headers are stored here */
+        private Hashtable<String, String> headers = new Hashtable<String, String>();
+
+        /* Create a new worker thread */
+        Worker() {
+            buf = new byte[BUF_SIZE];
+            s = null;
+        }
+
+        /**
+         * Called by the AcceptThread to unblock this Worker to process
+         * a request.
+         * @param s The socket on which the connection has been made
+         */
+        synchronized void setSocket(Socket s) {
+            this.s = s;
+            notify();
+        }
+
+        /**
+         * Called by the accept thread when it's closing. Potentially unblocks
+         * the worker thread to terminate properly
+         */
+        synchronized void close() {
+            running = false;
+            notify();
+        }
+
+        /**
+         * Main worker thread. This will wait until a request has
+         * been identified by the accept thread upon which it will
+         * service the thread.
+         */
+        public synchronized void run() {
+            running = true;
+            while(running) {
+                if (s == null) {
+                    /* nothing to do */
+                    try {
+                        log(this+" Moving to wait state");
+                        wait();
+                    } catch (InterruptedException e) {
+                        /* should not happen */
+                        continue;
+                    }
+                    if (!running) break;
+                }
+                try {
+                    handleClient();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                /* go back in wait queue if there's fewer
+                 * than numHandler connections.
+                 */
+                s = null;
+                Vector pool = threads;
+                synchronized (pool) {
+                    if (pool.size() >= workers) {
+                        /* too many threads, exit this one */
+                        activeThreads.remove(this);
+                        return;
+                    } else {
+                        pool.addElement(this);
+                    }
+                }
+            }
+            log(this+" terminated");
+        }
+
+        /**
+         * Zero out the buffer from last time
+         */
+        private void clearBuffer() {
+            for (int i = 0; i < BUF_SIZE; i++) {
+                buf[i] = 0;
+            }
+        }
+
+        /**
+         * Utility method to read a line of data from the input stream
+         * @param is Inputstream to read
+         * @return number of bytes read
+         */
+        private int readOneLine(InputStream is) {
+
+            int read = 0;
+
+            clearBuffer();
+            try {
+                log("Reading one line: started ="+readStarted+" avail="+is.available());
+                while ((!readStarted) || (is.available() > 0)) {
+                    int data = is.read();
+                    // We shouldn't get EOF but we need tdo check
+                    if (data == -1) {
+                        log("EOF returned");
+                        return -1;
+                    }
+
+                    buf[read] = (byte)data;
+
+                    System.out.print((char)data);
+
+                    readStarted = true;
+                    if (buf[read++]==(byte)'\n') {
+                        System.out.println();
+                        return read;
+                    }
+                }
+            } catch (IOException e) {
+                log("IOException from readOneLine");
+                e.printStackTrace();
+            }
+            return read;
+        }
+
+        /**
+         * Read a chunk of data
+         * @param is Stream from which to read data
+         * @param length Amount of data to read
+         * @return number of bytes read
+         */
+        private int readData(InputStream is, int length) {
+            int read = 0;
+            int count;
+            // At the moment we're only expecting small data amounts
+            byte[] buf = new byte[length];
+
+            try {
+                while (is.available() > 0) {
+                    count = is.read(buf, read, length-read);
+                    read += count;
+                }
+            } catch (IOException e) {
+                log("IOException from readData");
+                e.printStackTrace();
+            }
+            return read;
+        }
+
+        /**
+         * Read the status line from the input stream extracting method
+         * information.
+         * @param is Inputstream to read
+         * @return number of bytes read
+         */
+        private int parseStatusLine(InputStream is) {
+            int index;
+            int nread = 0;
+
+            log("Parse status line");
+            // Check for status line first
+            nread = readOneLine(is);
+            // Bomb out if stream closes prematurely
+            if (nread == -1) {
+                requestMethod = UNKNOWN_METHOD;
+                return -1;
+            }
+
+            if (buf[0] == (byte)'G' &&
+                buf[1] == (byte)'E' &&
+                buf[2] == (byte)'T' &&
+                buf[3] == (byte)' ') {
+                requestMethod = GET_METHOD;
+                log("GET request");
+                index = 4;
+            } else if (buf[0] == (byte)'H' &&
+                       buf[1] == (byte)'E' &&
+                       buf[2] == (byte)'A' &&
+                       buf[3] == (byte)'D' &&
+                       buf[4] == (byte)' ') {
+                requestMethod = HEAD_METHOD;
+                log("HEAD request");
+                index = 5;
+            } else if (buf[0] == (byte)'P' &&
+                       buf[1] == (byte)'O' &&
+                       buf[2] == (byte)'S' &&
+                       buf[3] == (byte)'T' &&
+                       buf[4] == (byte)' ') {
+                requestMethod = POST_METHOD;
+                log("POST request");
+                index = 5;
+            } else {
+                // Unhandled request
+                requestMethod = UNKNOWN_METHOD;
+                return -1;
+            }
+
+            // A valid method we understand
+            if (requestMethod > UNKNOWN_METHOD) {
+                // Read file name
+                int i = index;
+                while (buf[i] != (byte)' ') {
+                    // There should be HTTP/1.x at the end
+                    if ((buf[i] == (byte)'\n') || (buf[i] == (byte)'\r')) {
+                        requestMethod = UNKNOWN_METHOD;
+                        return -1;
+                    }
+                    i++;
+                }
+
+                testID = new String(buf, 0, index, i-index);
+                if (testID.startsWith("/")) {
+                    testID = testID.substring(1);
+                }
+
+                return nread;
+            }
+            return -1;
+        }
+
+        /**
+         * Read a header from the input stream
+         * @param is Inputstream to read
+         * @return number of bytes read
+         */
+        private int parseHeader(InputStream is) {
+            int index = 0;
+            int nread = 0;
+            log("Parse a header");
+            // Check for status line first
+            nread = readOneLine(is);
+            // Bomb out if stream closes prematurely
+            if (nread == -1) {
+                requestMethod = UNKNOWN_METHOD;
+                return -1;
+            }
+            // Read header entry 'Header: data'
+            int i = index;
+            while (buf[i] != (byte)':') {
+                // There should be an entry after the header
+
+                if ((buf[i] == (byte)'\n') || (buf[i] == (byte)'\r')) {
+                    return UNKNOWN_METHOD;
+                }
+                i++;
+            }
+
+            String headerName = new String(buf, 0, i);
+            i++; // Over ':'
+            while (buf[i] == ' ') {
+                i++;
+            }
+            String headerValue = new String(buf, i, nread-1);
+
+            headers.put(headerName, headerValue);
+            return nread;
+        }
+
+        /**
+         * Read all headers from the input stream
+         * @param is Inputstream to read
+         * @return number of bytes read
+         */
+        private int readHeaders(InputStream is) {
+            int nread = 0;
+            log("Read headers");
+            // Headers should be terminated by empty CRLF line
+            while (true) {
+                int headerLen = 0;
+                headerLen = parseHeader(is);
+                if (headerLen == -1)
+                    return -1;
+                nread += headerLen;
+                if (headerLen <= 2) {
+                    return nread;
+                }
+            }
+        }
+
+        /**
+         * Read content data from the input stream
+         * @param is Inputstream to read
+         * @return number of bytes read
+         */
+        private int readContent(InputStream is) {
+            int nread = 0;
+            log("Read content");
+            String lengthString = headers.get(requestHeaders[REQ_CONTENT_LENGTH]);
+            int length = new Integer(lengthString).intValue();
+
+            // Read content
+            length = readData(is, length);
+            return length;
+        }
+
+        /**
+         * The main loop, reading requests.
+         */
+        void handleClient() throws IOException {
+            InputStream is = new BufferedInputStream(s.getInputStream());
+            PrintStream ps = new PrintStream(s.getOutputStream());
+            int nread = 0;
+
+            /* we will only block in read for this many milliseconds
+             * before we fail with java.io.InterruptedIOException,
+             * at which point we will abandon the connection.
+             */
+            s.setSoTimeout(mTimeout);
+            s.setTcpNoDelay(true);
+
+            do {
+                nread = parseStatusLine(is);
+                if (requestMethod != UNKNOWN_METHOD) {
+
+                    // If status line found, read any headers
+                    nread = readHeaders(is);
+
+                    // Then read content (if any)
+                    // TODO handle chunked encoding from the client
+                    if (headers.get(requestHeaders[REQ_CONTENT_LENGTH]) != null) {
+                        nread = readContent(is);
+                    }
+                } else {
+                    if (nread > 0) {
+                        /* we don't support this method */
+                        ps.print(HTTP_VERSION_STRING + " " + HTTP_BAD_METHOD +
+                                 " unsupported method type: ");
+                        ps.write(buf, 0, 5);
+                        ps.write(EOL);
+                        ps.flush();
+                    } else {
+                    }
+                    if (!keepAlive || nread <= 0) {
+                        headers.clear();
+                        readStarted = false;
+
+                        log("SOCKET CLOSED");
+                        s.close();
+                        return;
+                    }
+                }
+
+                // Reset test number prior to outputing data
+                testNum = -1;
+
+                // Write out the data
+                printStatus(ps);
+                printHeaders(ps);
+
+                // Write line between headers and body
+                psWriteEOL(ps);
+
+                // Write the body
+                if (redirectCode == -1) {
+                    switch (requestMethod) {
+                        case GET_METHOD:
+                            if ((testNum < 0) || (testNum > TestWebData.tests.length - 1)) {
+                                send404(ps);
+                            } else {
+                                sendFile(ps);
+                            }
+                            break;
+                        case HEAD_METHOD:
+                            // Nothing to do
+                            break;
+                        case POST_METHOD:
+                            // Post method write body data
+                            if ((testNum > 0) || (testNum < TestWebData.tests.length - 1)) {
+                                sendFile(ps);
+                            }
+
+                            break;
+                        default:
+                            break;
+                    }
+                } else { // Redirecting
+                    switch (redirectCode) {
+                        case 301:
+                            // Seems 301 needs a body by neon (although spec
+                            // says SHOULD).
+                            psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_301]);
+                            break;
+                        case 302:
+                            //
+                            psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_302]);
+                            break;
+                        case 303:
+                            psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_303]);
+                            break;
+                        case 307:
+                            psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_307]);
+                            break;
+                        default:
+                            break;
+                    }
+                }
+
+                ps.flush();
+
+                // Reset for next request
+                readStarted = false;
+                headers.clear();
+
+            } while (keepAlive);
+
+            log("SOCKET CLOSED");
+            s.close();
+        }
+
+        // Print string to log and output stream
+        void psPrint(PrintStream ps, String s) throws IOException {
+            log(s);
+            ps.print(s);
+        }
+
+        // Print bytes to log and output stream
+        void psWrite(PrintStream ps, byte[] bytes, int len) throws IOException {
+            log(new String(bytes));
+            ps.write(bytes, 0, len);
+        }
+
+        // Print CRLF to log and output stream
+        void psWriteEOL(PrintStream ps) throws IOException {
+            log("CRLF");
+            ps.write(EOL);
+        }
+
+
+        // Print status to log and output stream
+        void printStatus(PrintStream ps) throws IOException {
+            // Handle redirects first.
+            if (redirectCode != -1) {
+                log("REDIRECTING TO "+redirectHost+" status "+redirectCode);
+                psPrint(ps, HTTP_VERSION_STRING + " " + redirectCode +" Moved permanently");
+                psWriteEOL(ps);
+                psPrint(ps, "Location: " + redirectHost);
+                psWriteEOL(ps);
+                return;
+            }
+
+
+            if (testID.startsWith("test")) {
+                testNum = Integer.valueOf(testID.substring(4))-1;
+            }
+
+            if ((testNum < 0) || (testNum > TestWebData.tests.length - 1)) {
+                psPrint(ps, HTTP_VERSION_STRING + " " + HTTP_NOT_FOUND + " not found");
+                psWriteEOL(ps);
+            }  else {
+                psPrint(ps, HTTP_VERSION_STRING + " " + HTTP_OK+" OK");
+                psWriteEOL(ps);
+            }
+
+            log("Status sent");
+        }
+        /**
+         * Create the server response and output to the stream
+         * @param ps The PrintStream to output response headers and data to
+         */
+        void printHeaders(PrintStream ps) throws IOException {
+            psPrint(ps,"Server: TestWebServer"+mPort);
+            psWriteEOL(ps);
+            psPrint(ps, "Date: " + (new Date()));
+            psWriteEOL(ps);
+            psPrint(ps, "Connection: " + ((keepAlive) ? "Keep-Alive" : "Close"));
+            psWriteEOL(ps);
+
+            // Yuk, if we're not redirecting, we add the file details
+            if (redirectCode == -1) {
+
+                if (!TestWebData.testParams[testNum].testDir) {
+                    if (chunked) {
+                        psPrint(ps, "Transfer-Encoding: chunked");
+                    } else {
+                        psPrint(ps, "Content-length: "+TestWebData.testParams[testNum].testLength);
+                    }
+                    psWriteEOL(ps);
+
+                    psPrint(ps,"Last Modified: " + (new
+                                                    Date(TestWebData.testParams[testNum].testLastModified)));
+                    psWriteEOL(ps);
+
+                    psPrint(ps, "Content-type: " + TestWebData.testParams[testNum].testType);
+                    psWriteEOL(ps);
+                } else {
+                    psPrint(ps, "Content-type: text/html");
+                    psWriteEOL(ps);
+                }
+            } else {
+                // Content-length of 301, 302, 303, 307 are the same.
+                psPrint(ps, "Content-length: "+(TestWebData.testServerResponse[TestWebData.REDIRECT_301]).length());
+                psWriteEOL(ps);
+                psWriteEOL(ps);
+            }
+            log("Headers sent");
+
+        }
+
+        /**
+         * Sends the 404 not found message
+         * @param ps The PrintStream to write to
+         */
+        void send404(PrintStream ps) throws IOException {
+            ps.println("Not Found\n\n"+
+                       "The requested resource was not found.\n");
+        }
+
+        /**
+         * Sends the data associated with the headers
+         * @param ps The PrintStream to write to
+         */
+        void sendFile(PrintStream ps) throws IOException {
+            // For now just make a chunk with the whole of the test data
+            // It might be worth making this multiple chunks for large
+            // test data to test multiple chunks.
+            int dataSize = TestWebData.tests[testNum].length;
+            if (chunked) {
+                psPrint(ps, Integer.toHexString(dataSize));
+                psWriteEOL(ps);
+                psWrite(ps, TestWebData.tests[testNum], dataSize);
+                psWriteEOL(ps);
+                psPrint(ps, "0");
+                psWriteEOL(ps);
+                psWriteEOL(ps);
+            } else {
+                psWrite(ps, TestWebData.tests[testNum], dataSize);
+            }
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/TreeMapTest.java b/tests/CoreTests/android/core/TreeMapTest.java
new file mode 100644
index 0000000..229d86d
--- /dev/null
+++ b/tests/CoreTests/android/core/TreeMapTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Random;
+import java.util.TreeMap;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Tests for basic functinality of TreeMaps
+ */
+public class TreeMapTest extends TestCase {
+
+    private Random mRandom = new Random(1);
+
+    private static final boolean SPEW = false;
+
+    @LargeTest
+    public void testTreeMap() {
+        for (int i = 0; i < 10; i++) {
+            if (SPEW) System.out.println("Running doTest cycle #" + (i + 1));
+            doTest();
+        }
+    }
+
+    private void doTest() {
+        TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
+        HashMap<Integer, String> hm = new HashMap<Integer, String>();
+
+        int minVal = Integer.MAX_VALUE;
+        int maxVal = Integer.MIN_VALUE;
+
+        for (int i = 0; i < 100; i++) {
+            int val = mRandom.nextInt(1000);
+            if (SPEW) System.out.println("Adding val = " + val);
+            if (val < minVal) {
+                minVal = val;
+            }
+            if (val > maxVal) {
+                maxVal = val;
+            }
+            tm.put(new Integer(val), "V:" + val);
+            hm.put(new Integer(val), "V:" + val);
+
+            if (SPEW) System.out.println("tm = " + tm);
+
+            if (SPEW) System.out.println("tm.size() = " + tm.size());
+            if (SPEW) System.out.println("hm.size() = " + hm.size());
+            assertEquals(tm.size(), hm.size());
+
+            if (SPEW) System.out.println("tm.firstKey() = " + tm.firstKey());
+            if (SPEW) System.out.println("minVal = " + minVal);
+            if (SPEW) System.out.println("tm.lastKey() = " + tm.lastKey());
+            if (SPEW) System.out.println("maxVal = " + maxVal);
+            assertEquals(minVal, tm.firstKey().intValue());
+            assertEquals(maxVal, tm.lastKey().intValue());
+        }
+
+        // Check for equality
+        for (int val = 0; val < 1000; val++) {
+            Integer vv = new Integer(val);
+            String tms = tm.get(vv);
+            String hms = hm.get(vv);
+            assertEquals(tms, hms);
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            int val = mRandom.nextInt(1000);
+            if (SPEW) System.out.println("Removing val = " + val);
+
+            String tms = tm.remove(new Integer(val));
+            String hms = hm.remove(new Integer(val));
+
+            if (SPEW) System.out.println("tm = " + tm);
+
+            assertEquals(tm.size(), hm.size());
+            assertEquals(tms, hms);
+        }
+
+        // Check for equality
+        for (int val = 0; val < 1000; val++) {
+            Integer vv = new Integer(val);
+            String tms = tm.get(vv);
+            String hms = hm.get(vv);
+            assertEquals(tms, hms);
+        }
+    }
+}
diff --git a/tests/CoreTests/android/core/URITest.java b/tests/CoreTests/android/core/URITest.java
new file mode 100644
index 0000000..3b821d8
--- /dev/null
+++ b/tests/CoreTests/android/core/URITest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class URITest extends TestCase {
+
+    @SmallTest
+    public void testConstruct() throws Exception {
+        construct("http://www.google.com/this/is-the/path?query#fragment",
+                "www.google.com", "/this/is-the/path", true);
+    }
+
+    private static void construct(String str, String host, String path, boolean absolute)
+            throws URISyntaxException {
+        URI uri = new URI(str);
+        assertEquals(host, uri.getHost());
+        assertEquals(path, uri.getPath());
+        assertEquals(absolute, uri.isAbsolute());
+    }
+
+    @SmallTest
+    public void testResolve() throws Exception {
+        resolve("http://www.google.com/your",
+                "mom",
+                "http://www.google.com/mom");
+    }
+
+    private static void resolve(String base, String uri, String expected) {
+        URI b = URI.create(base);
+        URI resolved = b.resolve(uri);
+//        System.out.println("base=" + base + " uri=" + uri
+//                + " resolved=" + resolved);
+        assertEquals(expected, resolved.toString());
+    }
+}
diff --git a/tests/CoreTests/android/core/URLTest.java b/tests/CoreTests/android/core/URLTest.java
new file mode 100644
index 0000000..56f9f7b
--- /dev/null
+++ b/tests/CoreTests/android/core/URLTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.net.URLConnection;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+@Suppress
+public class URLTest extends TestCase {
+
+    private static void get(String u) throws IOException {
+        URL url = new URL(u);
+        URLConnection cn = url.openConnection();
+        cn.connect();
+//        System.out.println("Content-Type: " + cn.getContentType());
+//        System.out.println("Content-Length: " + cn.getContentLength());
+
+        InputStream stream = cn.getInputStream();
+        if (stream == null) {
+            throw new RuntimeException("stream is null");
+        }
+        byte[] data = new byte[1024];
+        stream.read(data);
+
+//            if (true) {
+//                System.out.print("data=");
+//                System.out.write(data);
+//                System.out.println();
+//            }
+
+//                System.out.println("Content-Type: " + cn.getContentType());
+//                System.out.print("data:");
+//                System.out.write(data);
+//                System.out.println();
+
+        assertTrue(new String(data).indexOf("<html>") >= 0);
+    }
+
+    public void testGetHTTP() throws Exception {
+        get("http://www.google.com");
+    }
+
+    public void testGetHTTPS() throws Exception {
+        get("https://www.fortify.net/cgi/ssl_2.pl");
+    }
+
+    /**
+     * Dummy HTTP server class for testing keep-alive behavior. Listens a
+     * single time and responds to a given number of requests on the same
+     * socket. Then closes the socket.
+     */
+    private static class DummyServer implements Runnable {
+
+        private int keepAliveCount;
+
+        public DummyServer(int keepAliveCount) {
+            this.keepAliveCount = keepAliveCount;
+        }
+
+        public void run() {
+            try {
+                ServerSocket server = new ServerSocket(8182);
+                Socket socket = server.accept();
+
+                InputStream input = socket.getInputStream();
+                BufferedReader reader = new BufferedReader(new InputStreamReader(input));
+                try {
+                    for (int i = 0; i < keepAliveCount; i++) {
+                        String header = reader.readLine();
+                        while (header != null && header.length() != 0) {
+                            header = reader.readLine();
+                        }
+
+                        OutputStream output = socket.getOutputStream();
+                        PrintWriter writer = new PrintWriter(output);
+
+                        try {
+                            writer.println("HTTP/1.1 200 OK");
+                            String body = "Hello, Android world #" + i + "!";
+                            writer.println("Content-Length: " + body.length());
+                            writer.println("");
+                            writer.print(body);
+                            writer.flush();
+                        } finally {
+                            writer.close();
+                        }
+                    }
+                } finally {
+                    reader.close();
+                }
+                socket.close();
+                server.close();
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
+
+    /**
+     * Does a request to the given URL, reads and returns the result.
+     */
+    private String request(URL url) throws Exception {
+        URLConnection connection = url.openConnection();
+        connection.connect();
+
+        InputStream input = connection.getInputStream();
+        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
+        try {
+            return reader.readLine();
+        } finally {
+            reader.close();
+        }
+    }
+
+    /**
+     * Test case for HTTP keep-alive behavior.
+     */
+    public void testGetKeepAlive() throws Exception {
+        new Thread(new DummyServer(3)).start();
+        Thread.sleep(100);
+
+        // We expect the request to work three times, then it fails.
+        URL url = new URL("http://localhost:8182");
+        assertEquals("Hello, Android world #0!", request(url));
+        assertEquals("Hello, Android world #1!", request(url));
+        assertEquals("Hello, Android world #2!", request(url));
+
+        try {
+            request(url);
+            fail("ConnectException expected.");
+        } catch (Exception ex) {
+            // Ok.
+        }
+    }
+
+    /**
+     * Regression for issue 1001814.
+     */
+    public void testHttpConnectionTimeout() throws Exception {
+        int timeout = 5000;
+        HttpURLConnection cn = null;
+        long start = 0;
+        try {
+            start = System.currentTimeMillis();
+            URL url = new URL("http://123.123.123.123");
+            cn = (HttpURLConnection) url.openConnection();
+            cn.setConnectTimeout(5000);
+            cn.connect();
+            fail("should have thrown an exception");
+        } catch (IOException ioe) {
+            long delay = System.currentTimeMillis() - start;
+            if (Math.abs(timeout - delay) > 1000) {
+                fail("Timeout was not accurate. it needed " + delay +
+                        " instead of " + timeout + "miliseconds");
+            }
+        } finally {
+            if (cn != null) {
+                cn.disconnect();
+            }
+        }
+    }
+
+    /** 
+     * Regression test for issue 1158780 where using '{' and '}' in an URL threw
+     * an NPE. The RI accepts this URL and returns the status 404.
+     */ 
+    public void testMalformedUrl() throws Exception {
+        URL url = new URL("http://www.google.com/cgi-bin/myscript?g={United+States}+Borders+Mexico+{Climate+change}+Marketing+{Automotive+industry}+News+Health+Internet");
+        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+        int status = conn.getResponseCode();
+        android.util.Log.d("URLTest", "status: " + status);
+    }
+}
diff --git a/tests/CoreTests/android/core/ZipFileTest.java b/tests/CoreTests/android/core/ZipFileTest.java
new file mode 100644
index 0000000..04b476b
--- /dev/null
+++ b/tests/CoreTests/android/core/ZipFileTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import android.test.suitebuilder.annotation.MediumTest;
+
+
+/**
+ * Basic tests for ZipFile.
+ */
+public class ZipFileTest extends TestCase {
+    private static final int SAMPLE_SIZE = 128 * 1024;
+
+    @MediumTest
+    public void testZipFile() throws Exception {
+
+        File file = File.createTempFile("ZipFileTest", ".zip");
+        try {
+            // create a test file; assume it's not going to collide w/anything
+            FileOutputStream outStream = new FileOutputStream(file);
+            createCompressedZip(outStream);
+//            System.out.println("CREATED " + file);
+
+            scanZip(file.getPath());
+            read2(file.getPath());
+        } finally {
+            file.delete();
+        }
+    }
+
+    /*
+     * stepStep == 0 --> >99% compression
+     * stepStep == 1 --> ~30% compression
+     * stepStep == 2 --> no compression
+     */
+    static byte[] makeSampleFile(int stepStep) throws IOException {
+        byte[] sample = new byte[SAMPLE_SIZE];
+        byte val, step;
+        int i, j, offset;
+
+        val = 0;
+        step = 1;
+        offset = 0;
+        for (i = 0; i < SAMPLE_SIZE / 256; i++) {
+            for (j = 0; j < 256; j++) {
+                sample[offset++] = val;
+                val += step;
+            }
+
+            step += stepStep;
+        }
+
+        return sample;
+    }
+
+    static void createCompressedZip(OutputStream bytesOut) throws IOException {
+        ZipOutputStream out = new ZipOutputStream(bytesOut);
+        try {
+            int i;
+
+            for (i = 0; i < 3; i++) {
+                byte[] input = makeSampleFile(i);
+                ZipEntry newEntry = new ZipEntry("file-" + i);
+
+                if (i != 1) {
+                    newEntry.setComment("this is file " + i);
+                }
+                out.putNextEntry(newEntry);
+                out.write(input, 0, input.length);
+                out.closeEntry();
+            }
+
+            out.setComment("This is a lovely compressed archive!");
+        } finally {
+            out.close();
+        }
+    }
+
+    static void scanZip(String fileName) throws IOException {
+        ZipFile zipFile = new ZipFile(fileName);
+        Enumeration fileList;
+        int idx = 0;
+
+//        System.out.println("Contents of " + zipFile + ":");
+        for (fileList = zipFile.entries(); fileList.hasMoreElements();) {
+            ZipEntry entry = (ZipEntry) fileList.nextElement();
+//            System.out.println("  " + entry.getName());
+            assertEquals(entry.getName(), "file-" + idx);
+            idx++;
+        }
+
+        zipFile.close();
+    }
+
+    /*
+     * Read compressed data from two different entries at the same time,
+     * to verify that the streams aren't getting confused.  If we do
+     * something wrong, the inflater will choke and throw a ZipException.
+     *
+     * This doesn't test synchronization in multi-threaded use.
+     */
+    static void read2(String fileName) throws IOException {
+        ZipFile zipFile;
+        ZipEntry entry1, entry2;
+        byte buf[] = new byte[16384];
+        InputStream stream1, stream2;
+        int len, totalLen1, totalLen2;
+
+        /* use file-1 and file-2 because the compressed data is large */
+        zipFile = new ZipFile(fileName);
+        entry1 = zipFile.getEntry("file-1");
+        entry2 = zipFile.getEntry("file-2");
+
+        /* make sure we got the right thing */
+        assertEquals("file-1", entry1.getName());
+        assertEquals("file-2", entry2.getName());
+
+        /* create streams */
+        stream1 = zipFile.getInputStream(entry1);
+        stream2 = zipFile.getInputStream(entry2);
+
+        /*
+         * Read a piece of file #1.
+         */
+        totalLen1 = stream1.read(buf);
+        assertTrue("initial read failed on #1", totalLen1 >= 0);
+
+        /*
+         * Read a piece of file #2.
+         */
+        totalLen2 = stream2.read(buf);
+        assertTrue("initial read failed on #2", totalLen2 >= 0);
+
+        /*
+         * Read the rest of file #1, and close the stream.
+         *
+         * If our streams are crossed up, we'll fail here.
+         */
+        while ((len = stream1.read(buf)) > 0) {
+            totalLen1 += len;
+        }
+        assertEquals(SAMPLE_SIZE, totalLen1);
+        stream1.close();
+
+        /*
+         * Read the rest of file #2, and close the stream.
+         */
+        while ((len = stream2.read(buf)) > 0) {
+            totalLen2 += len;
+        }
+        assertEquals(SAMPLE_SIZE, totalLen2);
+        stream2.close();
+
+        /*
+         * Open a new one.
+         */
+        stream1 = zipFile.getInputStream(zipFile.getEntry("file-0"));
+
+        /*
+         * Close the ZipFile. According to the RI, none if its InputStreams can
+         * be read after this point.
+         */
+        zipFile.close();
+        
+        Exception error = null;
+        try {
+            stream1.read(buf);
+        } catch (Exception ex) {
+            error = ex;
+        }
+        
+        assertNotNull("ZipFile shouldn't allow reading of closed files.", error);
+    }
+}
+
diff --git a/tests/CoreTests/android/core/ZipStreamTest.java b/tests/CoreTests/android/core/ZipStreamTest.java
new file mode 100644
index 0000000..74cfe82
--- /dev/null
+++ b/tests/CoreTests/android/core/ZipStreamTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2008 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.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Basic tests for ZipStream
+ */
+public class ZipStreamTest extends TestCase {
+
+    @LargeTest
+    public void testZipStream() throws Exception {
+        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+        createCompressedZip(bytesOut);
+
+        byte[] zipData = bytesOut.toByteArray();
+
+        /*
+        FileOutputStream outFile = new FileOutputStream("/tmp/foo.zip");
+        outFile.write(zipData, 0, zipData.length);
+        outFile.close();
+        */
+
+        /*
+        FileInputStream inFile = new FileInputStream("/tmp/foo.zip");
+        int inputLength = inFile.available();
+        zipData = new byte[inputLength];
+        if (inFile.read(zipData) != inputLength)
+            throw new RuntimeException();
+        inFile.close();
+        */
+
+        ByteArrayInputStream bytesIn = new ByteArrayInputStream(zipData);
+        scanZip(bytesIn);
+
+        bytesOut = new ByteArrayOutputStream();
+        createUncompressedZip(bytesOut);
+
+        zipData = bytesOut.toByteArray();
+
+        bytesIn = new ByteArrayInputStream(zipData);
+        scanZip(bytesIn);
+    }
+
+    /*
+     * stepStep == 0 --> >99% compression
+     * stepStep == 1 --> ~30% compression
+     * stepStep == 2 --> no compression
+     */
+    private static byte[] makeSampleFile(int stepStep) throws IOException {
+        byte[] sample = new byte[128 * 1024];
+        byte val, step;
+        int i, j, offset;
+
+        val = 0;
+        step = 1;
+        offset = 0;
+        for (i = 0; i < (128 * 1024) / 256; i++) {
+            for (j = 0; j < 256; j++) {
+                sample[offset++] = val;
+                val += step;
+            }
+
+            step += stepStep;
+        }
+
+        return sample;
+    }
+
+    private static void createCompressedZip(ByteArrayOutputStream bytesOut) throws IOException {
+        ZipOutputStream out = new ZipOutputStream(bytesOut);
+        try {
+            int i;
+
+            for (i = 0; i < 3; i++) {
+                byte[] input = makeSampleFile(i);
+                ZipEntry newEntry = new ZipEntry("file-" + i);
+
+                if (i != 1)
+                    newEntry.setComment("this is file " + i);
+                out.putNextEntry(newEntry);
+                out.write(input, 0, input.length);
+                out.closeEntry();
+            }
+
+            out.setComment("This is a lovely compressed archive!");
+        } finally {
+            out.close();
+        }
+    }
+
+    private static void createUncompressedZip(ByteArrayOutputStream bytesOut) throws IOException {
+        ZipOutputStream out = new ZipOutputStream(bytesOut);
+        try {
+            long[] crcs = {0x205fbff3, 0x906fae57L, 0x2c235131};
+            int i;
+
+            for (i = 0; i < 3; i++) {
+                byte[] input = makeSampleFile(i);
+                ZipEntry newEntry = new ZipEntry("file-" + i);
+
+                if (i != 1)
+                    newEntry.setComment("this is file " + i);
+                newEntry.setMethod(ZipEntry.STORED);
+                newEntry.setSize(128 * 1024);
+                newEntry.setCrc(crcs[i]);
+                out.putNextEntry(newEntry);
+                out.write(input, 0, input.length);
+                out.closeEntry();
+            }
+
+            out.setComment("This is a lovely, but uncompressed, archive!");
+        } finally {
+            out.close();
+        }
+    }
+
+    private static void scanZip(ByteArrayInputStream bytesIn) throws IOException {
+        ZipInputStream in = new ZipInputStream(bytesIn);
+        try {
+            int i;
+
+            for (i = 0; i < 3; i++) {
+                ZipEntry entry = in.getNextEntry();
+                ByteArrayOutputStream contents = new ByteArrayOutputStream();
+                byte[] buf = new byte[4096];
+                int len, totalLen = 0;
+
+                while ((len = in.read(buf)) > 0) {
+                    contents.write(buf, 0, len);
+                    totalLen += len;
+                }
+
+                assertEquals(128 * 1024, totalLen);
+
+//                System.out.println("ZipStreamTest: name='" + entry.getName()
+//                        + "', zero=" + contents.toByteArray()[0]
+//                        + ", tfs=" + contents.toByteArray()[257]
+//                        + ", crc=" + Long.toHexString(entry.getCrc()));
+            }
+
+            assertNull("should only be three entries", in.getNextEntry());
+        } finally {
+            in.close();
+        }
+    }
+}
+
diff --git a/tests/CoreTests/android/database/MatrixCursorTest.java b/tests/CoreTests/android/database/MatrixCursorTest.java
new file mode 100644
index 0000000..fb8a12f
--- /dev/null
+++ b/tests/CoreTests/android/database/MatrixCursorTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2007 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.database;
+
+import junit.framework.TestCase;
+
+import java.util.*;
+
+public class MatrixCursorTest extends TestCase {
+
+    public void testEmptyCursor() {
+        Cursor cursor = new MatrixCursor(new String[] { "a" });
+        assertEquals(0, cursor.getCount());
+    }
+
+    public void testNullValue() {
+        MatrixCursor cursor = new MatrixCursor(new String[] { "a" });
+        cursor.newRow().add(null);
+        cursor.moveToNext();
+        assertTrue(cursor.isNull(0));
+    }
+
+    public void testMatrixCursor() {
+        MatrixCursor cursor = newMatrixCursor();
+
+        cursor.newRow()
+                .add("a")
+                .add(1)
+                .add(2)
+                .add(3)
+                .add(4)
+                .add(5);
+
+        cursor.moveToNext();
+
+        checkValues(cursor);
+
+        cursor.newRow()
+                .add("a")
+                .add("1")
+                .add("2")
+                .add("3")
+                .add("4")
+                .add("5");
+
+        cursor.moveToNext();
+        checkValues(cursor);
+
+        cursor.moveToPrevious();
+        checkValues(cursor);
+    }
+
+    public void testAddArray() {
+        MatrixCursor cursor = newMatrixCursor();
+
+        cursor.addRow(new Object[] { "a", 1, 2, 3, 4, 5 });
+        cursor.moveToNext();
+        checkValues(cursor);
+
+        try {
+            cursor.addRow(new Object[0]);
+            fail();
+        } catch (IllegalArgumentException e) { /* expected */ }
+    }
+
+    public void testAddIterable() {
+        MatrixCursor cursor = newMatrixCursor();
+
+        cursor.addRow(Arrays.asList("a", 1, 2, 3, 4, 5));
+        cursor.moveToNext();
+        checkValues(cursor);
+
+        try {
+            cursor.addRow(Collections.emptyList());
+            fail();
+        } catch (IllegalArgumentException e) { /* expected */ }
+
+        try {
+            cursor.addRow(Arrays.asList("a", 1, 2, 3, 4, 5, "Too many!"));
+            fail();
+        } catch (IllegalArgumentException e) { /* expected */ }
+    }
+
+    public void testAddArrayList() {
+        MatrixCursor cursor = newMatrixCursor();
+
+        cursor.addRow(new NonIterableArrayList<Object>(
+                Arrays.asList("a", 1, 2, 3, 4, 5)));
+        cursor.moveToNext();
+        checkValues(cursor);
+
+        try {
+            cursor.addRow(new NonIterableArrayList<Object>());
+            fail();
+        } catch (IllegalArgumentException e) { /* expected */ }
+
+        try {
+            cursor.addRow(new NonIterableArrayList<Object>(
+                    Arrays.asList("a", 1, 2, 3, 4, 5, "Too many!")));
+            fail();
+        } catch (IllegalArgumentException e) { /* expected */ }
+    }
+
+    static class NonIterableArrayList<T> extends ArrayList<T> {
+
+        NonIterableArrayList() {}
+
+        NonIterableArrayList(Collection<? extends T> ts) {
+            super(ts);
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            throw new AssertionError();
+        }
+    }
+
+    private MatrixCursor newMatrixCursor() {
+        return new MatrixCursor(new String[] {
+                "string", "short", "int", "long", "float", "double" });
+    }
+
+    private void checkValues(MatrixCursor cursor) {
+        assertEquals("a", cursor.getString(0));
+        assertEquals(1, cursor.getShort(1));
+        assertEquals(2, cursor.getInt(2));
+        assertEquals(3, cursor.getLong(3));
+        assertEquals(4.0f, cursor.getFloat(4));
+        assertEquals(5.0D, cursor.getDouble(5));
+    }
+
+}
diff --git a/tests/CoreTests/android/graphics/ColorStateListTest.java b/tests/CoreTests/android/graphics/ColorStateListTest.java
new file mode 100644
index 0000000..68c2fc1
--- /dev/null
+++ b/tests/CoreTests/android/graphics/ColorStateListTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 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.graphics;
+
+import android.content.res.Resources;
+import android.content.res.ColorStateList;
+import android.test.AndroidTestCase;
+import android.core.R;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests of {@link android.graphics.ColorStateList}
+ */
+
+public class ColorStateListTest extends AndroidTestCase {
+
+    private Resources mResources;
+    private int mFailureColor;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mResources = mContext.getResources();
+        mFailureColor = mResources.getColor(R.color.failColor);
+    }
+
+    @SmallTest
+    public void testStateIsInList() throws Exception {
+        ColorStateList colorStateList = mResources.getColorStateList(R.color.color1);
+        int[] focusedState = {android.R.attr.state_focused};
+        int focusColor = colorStateList.getColorForState(focusedState, R.color.failColor);
+        assertEquals(mResources.getColor(R.color.testcolor1), focusColor);
+    }
+
+    @SmallTest
+    public void testEmptyState() throws Exception {
+        ColorStateList colorStateList = mResources.getColorStateList(R.color.color1);
+        int[] emptyState = {};
+        int defaultColor = colorStateList.getColorForState(emptyState, mFailureColor);
+        assertEquals(mResources.getColor(R.color.testcolor2), defaultColor);
+    }
+
+    @SmallTest
+    public void testGetColor() throws Exception {
+        int defaultColor = mResources.getColor(R.color.color1);
+        assertEquals(mResources.getColor(R.color.testcolor2), defaultColor);
+    }
+
+    @SmallTest
+    public void testGetColorWhenListHasNoDefault() throws Exception {
+        int defaultColor = mResources.getColor(R.color.color_no_default);
+        assertEquals(mResources.getColor(R.color.testcolor1), defaultColor);
+    }
+}
diff --git a/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java b/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java
new file mode 100644
index 0000000..0d9f72e
--- /dev/null
+++ b/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007 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.graphics.drawable;
+
+import junit.framework.TestCase;
+
+import android.R;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.util.StateSet;
+import android.view.MockView;
+
+/**
+ * Tests for StateListDrawable
+ *
+ */
+
+public class StateListDrawableTest extends TestCase {
+
+    private StateListDrawable slDrawable;
+    private MockDrawable mockFocusedDrawable;
+    private MockDrawable mockCheckedDrawable;
+    private MockView mockView;
+    private MockDrawable mockDefaultDrawable;
+
+
+    // Re-enable tests when we are running in the framework-test directory which allows
+    // access to package private access for MockView
+
+    public void broken_testFocusScenarioSetStringWildcardFirst() throws Exception {
+        int focusedStateSet[] = {R.attr.state_focused};
+        int checkedStateSet[] = {R.attr.state_checked};
+        slDrawable.addState(StateSet.WILD_CARD,
+                               mockDefaultDrawable);
+        slDrawable.addState(checkedStateSet, mockCheckedDrawable);
+        slDrawable.addState(focusedStateSet, mockFocusedDrawable);
+        mockView.requestFocus();
+        mockView.getBackground().draw(null);
+        assertTrue(mockDefaultDrawable.wasDrawn);
+    }
+
+    public void broken_testFocusScenarioStateSetWildcardLast() throws Exception {
+        int focusedStateSet[] = {R.attr.state_focused};
+        int checkedStateSet[] = {R.attr.state_checked};
+        slDrawable.addState(checkedStateSet, mockCheckedDrawable);
+        slDrawable.addState(focusedStateSet, mockFocusedDrawable);
+        slDrawable.addState(StateSet.WILD_CARD,
+                               mockDefaultDrawable);
+        mockView.requestFocus();
+        mockView.getBackground().draw(null);
+        assertTrue(mockFocusedDrawable.wasDrawn);
+    }
+
+ 
+    protected void setUp() throws Exception {
+        super.setUp();
+        slDrawable = new StateListDrawable();
+        mockFocusedDrawable = new MockDrawable();
+        mockCheckedDrawable = new MockDrawable();
+        mockDefaultDrawable = new MockDrawable();
+        mockView = new MockView();
+        mockView.setBackgroundDrawable(slDrawable);
+    }
+
+    static class MockDrawable extends Drawable {
+
+        public boolean wasDrawn = false;
+
+        public void draw(Canvas canvas) {
+            wasDrawn = true;
+        }
+
+        public void setAlpha(int alpha) {
+        }
+
+        public void setColorFilter(ColorFilter cf) {
+        }
+
+        public int getOpacity() {
+            return android.graphics.PixelFormat.UNKNOWN;
+        }
+    }
+
+}
diff --git a/tests/CoreTests/android/location/LocationManagerProximityTest.java b/tests/CoreTests/android/location/LocationManagerProximityTest.java
new file mode 100644
index 0000000..e1501e3
--- /dev/null
+++ b/tests/CoreTests/android/location/LocationManagerProximityTest.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.location;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+
+/**
+ * Tests for LocationManager.addProximityAlert
+ * 
+ * TODO: add tests for more scenarios
+ * 
+ * To run:
+ *  adb shell am instrument -e class android.location.LocationManagerProximityTest \
+ *     -w android.core/android.test.InstrumentationTestRunner
+ *     
+ * This test requires that the "Allow mock locations" setting be enabled     
+ * 
+ */
+@MediumTest
+public class LocationManagerProximityTest extends AndroidTestCase {
+
+    private static final int UPDATE_LOCATION_WAIT_TIME = 1000;
+    private static final int PROXIMITY_WAIT_TIME = 2000;
+
+    private LocationManager mLocationManager;
+    private PendingIntent mPendingIntent;
+    private TestIntentReceiver mIntentReceiver;
+
+    private static final String LOG_TAG = "LocationProximityTest";
+
+    // use network provider as mock location provider, because:
+    //  - proximity alert is hardcoded to listen to only network or gps
+    //  - 'network' provider is not installed in emulator, so can mock it 
+    //    using test provider APIs
+    private static final String PROVIDER_NAME = LocationManager.NETWORK_PROVIDER;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // test that mock locations are allowed so a more descriptive error message can be logged
+        if (Settings.Secure.getInt(getContext().getContentResolver(),
+            Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) {
+            fail("Mock locations are currently disabled in Settings - this test requires " +
+                 "mock locations");
+        }
+
+        mLocationManager = (LocationManager) getContext().
+                getSystemService(Context.LOCATION_SERVICE);
+        if (mLocationManager.getProvider(PROVIDER_NAME) != null) {
+            mLocationManager.removeTestProvider(PROVIDER_NAME);
+        }
+        
+        mLocationManager.addTestProvider(PROVIDER_NAME, true, //requiresNetwork,
+                false, // requiresSatellite,
+                true, // requiresCell,
+                false, // hasMonetaryCost,
+                false, // supportsAltitude,
+                false, // supportsSpeed, s
+                false, // upportsBearing,
+                Criteria.POWER_MEDIUM, // powerRequirement
+                Criteria.ACCURACY_FINE); // accuracy
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mLocationManager.removeTestProvider(PROVIDER_NAME);
+
+        if (mPendingIntent != null) {
+            mLocationManager.removeProximityAlert(mPendingIntent);
+        }
+        if (mIntentReceiver != null) {
+            getContext().unregisterReceiver(mIntentReceiver);
+        }
+    }
+
+    /**
+     * Tests basic proximity alert when entering proximity
+     */
+    public void testEnterProximity() throws Exception {
+        doTestEnterProximity(10000);
+    }
+
+    /**
+     * Tests proximity alert when entering proximity, with no expiration 
+     */
+    public void testEnterProximity_noexpire() throws Exception {
+        doTestEnterProximity(-1);
+    }
+
+    /**
+     * Helper variant for testing enter proximity scenario 
+     * TODO: add additional parameters as more scenarios are added
+     * 
+     * @param expiration - expiry of proximity alert 
+     */
+    private void doTestEnterProximity(long expiration) throws Exception {
+        // update location to outside proximity range
+        synchronousSendLocation(30, 30);
+        registerProximityListener(0, 0, 1000, expiration);
+        sendLocation(0, 0);
+        waitForAlert();
+        assertProximityType(true);
+    }
+
+    /**
+     * Tests basic proximity alert when exiting proximity
+     */
+    public void testExitProximity() throws Exception {
+        // first do enter proximity scenario
+        doTestEnterProximity(-1);
+
+        // now update to trigger exit proximity proximity
+        mIntentReceiver.clearReceivedIntents();
+        sendLocation(20, 20);
+        waitForAlert();
+        assertProximityType(false);
+    }
+
+    /**
+     * Registers the proximity intent receiver
+     */
+    private void registerProximityListener(double latitude, double longitude, 
+            float radius, long expiration) {
+        String intentKey = "testProximity";
+        Intent proximityIntent = new Intent(intentKey);
+        mPendingIntent = PendingIntent.getBroadcast(getContext(), 0, 
+                proximityIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+        mIntentReceiver = new TestIntentReceiver(intentKey);
+
+        mLocationManager.addProximityAlert(latitude, longitude, radius, 
+                expiration, mPendingIntent);
+
+        getContext().registerReceiver(mIntentReceiver, 
+                mIntentReceiver.getFilter());
+
+    }
+
+    /**
+     * Blocks until proximity intent notification is received
+     * @throws InterruptedException
+     */
+    private void waitForAlert() throws InterruptedException {
+        Log.d(LOG_TAG, "Waiting for proximity update");
+        synchronized (mIntentReceiver) {
+            mIntentReceiver.wait(PROXIMITY_WAIT_TIME);
+        }
+
+        assertNotNull("Did not receive proximity alert", 
+                mIntentReceiver.getLastReceivedIntent());
+    }
+
+    /**
+     * Asserts that the received intent had the enter proximity property set as
+     * expected
+     * @param expectedEnterProximity - true if enter proximity expected, false if
+     *   exit expected
+     */
+    private void assertProximityType(boolean expectedEnterProximity) 
+            throws Exception {
+        boolean proximityTest = mIntentReceiver.getLastReceivedIntent().
+                getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING, 
+                !expectedEnterProximity);
+        assertEquals("proximity alert not set to expected enter proximity value",
+                expectedEnterProximity, proximityTest);
+    }
+
+    /**
+     * Synchronous variant of sendLocation
+     */
+    private void synchronousSendLocation(final double latitude, 
+            final double longitude)
+            throws InterruptedException {
+        sendLocation(latitude, longitude, this);
+        // wait for location to be set
+        synchronized (this) {
+            wait(UPDATE_LOCATION_WAIT_TIME);
+        }
+    }
+
+    /**
+     * Asynchronously update the mock location provider without notification
+     */
+    private void sendLocation(final double latitude, final double longitude) {
+        sendLocation(latitude, longitude, null);
+    }
+
+    /**
+     * Asynchronously update the mock location provider with given latitude and
+     * longitude
+     * 
+     * @param latitude - update location
+     * @param longitude - update location
+     * @param observer - optionally, object to notify when update is sent.If
+     *            null, no update will be sent
+     */
+    private void sendLocation(final double latitude, final double longitude, 
+            final Object observer) {
+        Thread locationUpdater = new Thread() {
+            @Override
+            public void run() {
+                Location loc = new Location(PROVIDER_NAME);
+                loc.setLatitude(latitude);
+                loc.setLongitude(longitude);
+
+                loc.setTime(java.lang.System.currentTimeMillis());
+                Log.d(LOG_TAG, "Sending update for " + PROVIDER_NAME);
+                mLocationManager.setTestProviderLocation(PROVIDER_NAME, loc);
+                if (observer != null) {
+                    synchronized (observer) {
+                        observer.notify();
+                    }
+                }
+            }
+        };
+        locationUpdater.start();
+
+    }
+
+    /**
+     * Helper class that receives a proximity intent and notifies the main class
+     * when received
+     */
+    private static class TestIntentReceiver extends BroadcastReceiver {
+
+        private String mExpectedAction;
+        private Intent mLastReceivedIntent;
+
+        public TestIntentReceiver(String expectedAction) {
+            mExpectedAction = expectedAction;
+            mLastReceivedIntent = null;
+        }
+
+        public IntentFilter getFilter() {
+            IntentFilter filter = new IntentFilter(mExpectedAction);
+            return filter;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent != null && mExpectedAction.equals(intent.getAction())) {
+                Log.d(LOG_TAG, "Intent Received: " + intent.toString());
+                mLastReceivedIntent = intent;
+                synchronized (this) {
+                    notify();
+                }
+            }
+        }
+
+        public Intent getLastReceivedIntent() {
+            return mLastReceivedIntent;
+        }
+        
+        public void clearReceivedIntents() {
+            mLastReceivedIntent = null;
+        }
+    }
+}
diff --git a/tests/CoreTests/android/location/LocationTest.java b/tests/CoreTests/android/location/LocationTest.java
new file mode 100644
index 0000000..847ac7a
--- /dev/null
+++ b/tests/CoreTests/android/location/LocationTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * 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.location;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for android.location.Location
+ */
+@SmallTest
+public class LocationTest extends TestCase {
+
+    // ***** Tests for Location.convert
+    public void testConvert_DegreesToDouble(){
+        String testDegreesCoord = "-80.075";
+        String message;
+        double result;
+
+        result = Location.convert(testDegreesCoord);
+        message = "degreesToDoubleTest: Double should be -80.075, actual value is " +
+                String.valueOf(result);
+        assertEquals(message, -80.075, result);
+    }
+    
+    public void testConvert_MinutesToDouble(){
+        String testMinutesCoord = "-80:05.10000";
+        String message;
+        double result;
+
+        result = Location.convert(testMinutesCoord);
+        message = "minutesToDoubleTest: Double should be -80.085, actual value is " +
+                String.valueOf(result);
+        assertEquals(message, -80.085, result);
+    }
+    
+    public void testConvert_SecondsToDouble(){
+        String testSecondsCoord = "-80:04:03.00000";
+        String message;
+        double result;
+
+        result = Location.convert(testSecondsCoord);
+        message = "secondsToDoubleTest: Double should be -80.0675, actual value is " +
+                String.valueOf(result);
+        assertEquals(message, -80.0675, result);
+    }
+    
+    public void testConvert_SecondsToDouble2(){
+        String testSecondsCoord = "-80:4:3";
+        String message;
+        double result;
+
+        result = Location.convert(testSecondsCoord);
+        message = "secondsToDouble2Test: Double should be -80.0675, actual value is " +
+                String.valueOf(result);
+        assertEquals(message, -80.0675, result);
+    }
+
+    // Testing the Convert(Double, Int)
+    public void testConvert_CoordinateToDegrees(){
+        String message;
+        String result;
+
+        result = Location.convert(-80.075, Location.FORMAT_DEGREES);
+        message = "coordinateToDegreesTest: Should return a string -80.075, but returned " + result;
+        assertEquals(message, "-80.075", result);
+    }
+    
+    public void testConvert_CoordinateToDegrees2(){
+        String message;
+        String result;
+        result = Location.convert(-80.0, Location.FORMAT_DEGREES);
+        message = "coordinateToDegrees2Test: Should return a string -80, but returned " + result;
+        assertEquals(message, "-80", result);
+    }
+    
+    public void testConvert_CoordinateToMinutes(){
+        String message;
+        String result;
+        double input = -80.085;
+        result = Location.convert(input, Location.FORMAT_MINUTES);
+        message = "coordinateToMinuteTest: Should return a string -80:5.1, but returned " +
+                result;
+        assertEquals(message, "-80:5.1", result);
+    }
+    
+    public void testConvert_CoordinateToMinutes2(){
+        String message;
+        String result;
+        double input = -80;
+        result = Location.convert(input, Location.FORMAT_MINUTES);
+        message = "coordinateToMinute2Test: Should return a string -80:0, but returned " +
+                result;
+        assertEquals(message, "-80:0", result);
+    }
+    
+    public void testConvert_CoordinateToSeconds(){
+        String message;
+        String result;
+
+        result = Location.convert(-80.075, Location.FORMAT_SECONDS);
+        message = "coordinateToSecondsTest: Should return a string -80:4:30, but returned " +
+                result;
+        assertEquals(message, "-80:4:30", result);
+    }
+    // **** end tests for Location.convert
+
+
+    public void testBearingTo(){
+        String message;
+        float bearing;
+        Location zeroLocation = new Location("");
+        zeroLocation.setLatitude(0);
+        zeroLocation.setLongitude(0);
+
+        Location testLocation = new Location("");
+        testLocation.setLatitude(1000000);
+        testLocation.setLongitude(0);
+
+        bearing = zeroLocation.bearingTo(zeroLocation);
+        message = "bearingToTest: Bearing should be 0, actual value is " + String.valueOf(bearing);
+        assertEquals(message, 0, bearing, 0);
+
+        bearing = zeroLocation.bearingTo(testLocation);
+        message = "bearingToTest: Bearing should be 180, actual value is " +
+                String.valueOf(bearing);
+        assertEquals(message, 180, bearing, 0);
+
+        testLocation.setLatitude(0);
+        testLocation.setLongitude(1000000);
+        bearing = zeroLocation.bearingTo(testLocation);
+        message = "bearingToTest: Bearing should be -90, actual value is " +
+                String.valueOf(bearing);
+        assertEquals(message, -90, bearing, 0);
+
+        //TODO: Test a Random Middle Value
+    }
+    
+    public void testDistanceTo() {
+        String message;
+        boolean result = true;
+        float distance;
+        Location zeroLocation = new Location("");
+        zeroLocation.setLatitude(0);
+        zeroLocation.setLongitude(0);
+
+        Location testLocation = new Location("");
+        testLocation.setLatitude(1000000);
+        testLocation.setLongitude(0);
+
+        distance = zeroLocation.distanceTo(zeroLocation);
+        message = "distanceToTest: Distance should be 0, actual value is " +
+        String.valueOf(distance);
+        assertEquals(message, distance, 0, 0);
+
+        distance = zeroLocation.distanceTo(testLocation);
+        message = "distanceToTest: Distance should be 8885140, actual value is " +
+        String.valueOf(distance);
+        assertEquals(message, distance, 8885140.0, 1);
+    }
+    
+    public void testAltitude() {
+        String message;
+        Location loc = new Location("");
+
+        loc.setAltitude(1);
+        message = "altitudeTest: set/getAltitude to 1 didn't work.";
+        assertEquals(message, loc.getAltitude(), 1, 0);
+        message = "altitudeTest: hasAltitude (a) didn't work.";
+        assertTrue(message, loc.hasAltitude());
+
+        loc.removeAltitude();
+        message = "altitudeTest: hasAltitude (b) didn't work.";
+        assertFalse(message, loc.hasAltitude());
+        message = "altitudeTest: getAltitude didn't return 0 when there was no altitude.";
+        assertEquals(message, loc.getAltitude(), 0, 0);
+    }
+
+    public void testSpeed() {
+        String message;
+        Location loc = new Location("");
+
+        loc.setSpeed(1);
+        message = "speedTest: set/getSpeed to 1 didn't work.";
+        assertEquals(message, loc.getSpeed(), 1, 0);
+        message = "speedTest: hasSpeed (a) didn't work.";
+        assertTrue(message, loc.hasSpeed());
+
+        loc.removeSpeed();
+        message = "speedTest: hasSpeed (b) didn't work.";
+        assertFalse(message, loc.hasSpeed());
+        message = "speedTest: getSpeed didn't return 0 when there was no speed.";
+        assertEquals(message, loc.getSpeed(), 0, 0);
+    }
+
+    public void testBearing() {
+        String message;
+        Location loc = new Location("");
+
+        loc.setBearing(1);
+        message = "bearingTest: set/getBearing to 1 didn't work.";
+        assertEquals(message, loc.getBearing(), 1, 0);
+        message = "bearingTest: hasBearing (a) didn't work.";
+        assertTrue(message, loc.hasBearing());
+
+        loc.removeBearing();
+        message = "bearingTest: hasBearing (b) didn't work.";
+        assertFalse(message, loc.hasBearing());
+        message = "bearingTest: getBearing didn't return 0 when there was no bearing.";
+        assertEquals(message, loc.getBearing(), 0, 0);
+    }
+
+}
+
+
diff --git a/tests/CoreTests/android/res/color/color1.xml b/tests/CoreTests/android/res/color/color1.xml
new file mode 100644
index 0000000..87034fa
--- /dev/null
+++ b/tests/CoreTests/android/res/color/color1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:color="@color/testcolor1"/>
+    <item android:color="@color/testcolor2"/>
+</selector>
diff --git a/tests/CoreTests/android/res/color/color_no_default.xml b/tests/CoreTests/android/res/color/color_no_default.xml
new file mode 100644
index 0000000..41a9b5d
--- /dev/null
+++ b/tests/CoreTests/android/res/color/color_no_default.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true" android:color="@color/testcolor1"/>
+</selector>
diff --git a/tests/CoreTests/android/res/values/colors.xml b/tests/CoreTests/android/res/values/colors.xml
new file mode 100644
index 0000000..7559e65
--- /dev/null
+++ b/tests/CoreTests/android/res/values/colors.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <color name="testcolor1">#ff00ff00</color>
+    <color name="testcolor2">#ffff0000</color>
+    <color name="failColor">#ff0000ff</color>
+</resources>
+
diff --git a/tests/CoreTests/android/test/AndroidTestRunnerTest.java b/tests/CoreTests/android/test/AndroidTestRunnerTest.java
new file mode 100644
index 0000000..0574704
--- /dev/null
+++ b/tests/CoreTests/android/test/AndroidTestRunnerTest.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2008 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.test;
+
+import android.test.mock.MockContext;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.TestCase;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.framework.TestListener;
+
+import java.util.List;
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link AndroidTestRunner}
+ */
+@SmallTest
+public class AndroidTestRunnerTest extends TestCase {
+    private AndroidTestRunner mAndroidTestRunner;
+    private StubContext mStubContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mStubContext = new StubContext(getClass().getClassLoader());
+
+        mAndroidTestRunner = new AndroidTestRunner();
+        mAndroidTestRunner.setContext(mStubContext);
+    }
+
+    public void testLoadNoTestCases() throws Exception {
+        mAndroidTestRunner.setTestClassName(TestSuite.class.getName(), null);
+
+        List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+        assertNotNull(testCases);
+        assertEquals(1, testCases.size());
+        assertEquals("warning", testCases.get(0).getName());
+        assertEquals(TestSuite.class.getSimpleName(), mAndroidTestRunner.getTestClassName());
+    }
+
+    public void testSetTestSuiteWithOneTestCase() throws Exception {
+        mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null);
+
+        List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+        assertNotNull(testCases);
+        assertEquals(1, testCases.size());
+        assertEquals("testOne", testCases.get(0).getName());
+        assertEquals(OneTestTestCase.class.getSimpleName(), mAndroidTestRunner.getTestClassName());
+    }
+
+    public void testRunTest() throws Exception {
+        mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null);
+
+        TestListenerStub testListenerStub = new TestListenerStub();
+        mAndroidTestRunner.addTestListener(testListenerStub);
+
+        mAndroidTestRunner.runTest();
+
+        assertTrue(testListenerStub.saw("testOne"));
+    }
+
+    public void testRunTestWithAndroidTestCase() throws Exception {
+        mAndroidTestRunner.setTestClassName(
+                OneAndroidTestTestCase.class.getName(), "testOneAndroid");
+
+        TestListenerStub testListenerStub = new TestListenerStub();
+        mAndroidTestRunner.addTestListener(testListenerStub);
+
+        assertNull(((AndroidTestCase) mAndroidTestRunner.getTestCases().get(0)).getContext());
+
+        mAndroidTestRunner.runTest();
+
+        assertTrue(testListenerStub.saw("testOneAndroid"));
+        assertSame(mStubContext,
+                ((AndroidTestCase) mAndroidTestRunner.getTestCases().get(0)).getContext());
+    }
+
+    public void testRunTestWithAndroidTestCaseInSuite() throws Exception {
+        mAndroidTestRunner.setTestClassName(OneAndroidTestTestCase.class.getName(), null);
+
+        TestListenerStub testListenerStub = new TestListenerStub();
+        mAndroidTestRunner.addTestListener(testListenerStub);
+
+        mAndroidTestRunner.runTest();
+
+        assertTrue(testListenerStub.saw("testOneAndroid"));
+
+        List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+        for (TestCase testCase : testCases) {
+            assertSame(mStubContext, ((AndroidTestCase) testCase).getContext());
+        }
+    }
+
+    public void testRunTestWithAndroidTestCaseInNestedSuite() throws Exception {
+        mAndroidTestRunner.setTestClassName(AndroidTestCaseTestSuite.class.getName(), null);
+
+        TestListenerStub testListenerStub = new TestListenerStub();
+        mAndroidTestRunner.addTestListener(testListenerStub);
+
+        mAndroidTestRunner.runTest();
+
+        assertTrue(testListenerStub.saw("testOneAndroid"));
+
+        List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+        for (TestCase testCase : testCases) {
+            assertSame(mStubContext, ((AndroidTestCase) testCase).getContext());
+        }
+    }
+
+    public void testRunTestWithNullListener() throws Exception {
+        mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null);
+
+        mAndroidTestRunner.addTestListener(null);
+        try {
+            mAndroidTestRunner.runTest();
+        } catch (NullPointerException e) {
+            fail("Should not add a null TestListener");
+        }
+    }
+
+    public void testSetTestClassWithTestSuiteProvider() throws Exception {
+        mAndroidTestRunner.setTestClassName(SampleTestSuiteProvider.class.getName(), null);
+        List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+        List<String> testNames = Lists.newArrayList();
+        for (TestCase testCase : testCases) {
+            testNames.add(testCase.getName());
+        }
+
+        // Use the test suite provided by the interface method rather than the static suite method.
+        assertEquals(Arrays.asList("testOne"), testNames);
+    }
+
+    public void testSetTestClassWithTestSuite() throws Exception {
+        mAndroidTestRunner.setTestClassName(SampleTestSuite.class.getName(), null);
+        List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+        List<String> testNames = Lists.newArrayList();
+        for (TestCase testCase : testCases) {
+            testNames.add(testCase.getName());
+        }
+        assertEquals(Arrays.asList("testOne", "testOne", "testTwo"), testNames);
+    }
+
+    public void testRunSingleTestMethod() throws Exception {
+        String testMethodName = "testTwo";
+        mAndroidTestRunner.setTestClassName(TwoTestTestCase.class.getName(), testMethodName);
+        List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+        List<String> testNames = Lists.newArrayList();
+        for (TestCase testCase : testCases) {
+            testNames.add(testCase.getName());
+        }
+        assertEquals(Arrays.asList(testMethodName), testNames);
+    }
+
+    public void testSetTestClassInvalidClass() throws Exception {
+        try {
+            mAndroidTestRunner.setTestClassName("class.that.does.not.exist", null);
+            fail("expected exception not thrown");
+        } catch (RuntimeException e) {
+            // expected
+        }
+    }
+    
+    public void testRunSkipExecution() throws Exception {
+        String testMethodName = "testFail";
+        mAndroidTestRunner.setTestClassName(
+                OnePassOneErrorOneFailTestCase.class.getName(), testMethodName);
+        
+        TestListenerStub testListenerStub = new TestListenerStub();
+        mAndroidTestRunner.addTestListener(testListenerStub);
+        
+        // running the failing test should pass - ie as if its not run
+        mAndroidTestRunner.runTest();
+        
+        assertTrue(testListenerStub.saw("testFail"));
+    }
+
+    public static class SampleTestSuiteProvider implements TestSuiteProvider {
+
+        public TestSuite getTestSuite() {
+            TestSuite testSuite = new TestSuite();
+            testSuite.addTestSuite(OneTestTestCase.class);
+            return testSuite;
+        }
+
+        public static Test suite() {
+            return SampleTestSuite.suite();
+        }
+    }
+
+    public static class SampleTestSuite {
+        public static TestSuite suite() {
+            TestSuite testSuite = new TestSuite();
+            testSuite.addTestSuite(OneTestTestCase.class);
+            testSuite.addTestSuite(TwoTestTestCase.class);
+            return testSuite;
+        }
+    }
+
+    public static class AndroidTestCaseTestSuite {
+        public static TestSuite suite() {
+            TestSuite testSuite = new TestSuite();
+            testSuite.addTestSuite(OneAndroidTestTestCase.class);
+            return testSuite;
+        }
+    }
+
+    public static class OneAndroidTestTestCase extends AndroidTestCase {
+        public void testOneAndroid() throws Exception {
+        }
+    }
+
+    public static class OneTestTestCase extends TestCase {
+        public void testOne() throws Exception {
+        }
+    }
+
+    public static class TwoTestTestCase extends TestCase {
+        public void testOne() throws Exception {
+        }
+
+        public void testTwo() throws Exception {
+        }
+    }
+
+    public static class OnePassOneErrorOneFailTestCase extends TestCase {
+        public void testPass() throws Exception {
+        }
+
+        public void testError() throws Exception {
+            throw new Exception();
+        }
+
+        public void testFail() throws Exception {
+            fail();
+        }
+    }
+
+    private static class TestListenerStub implements TestListener {
+        List<String> testNames = Lists.newArrayList();
+
+        public void addError(Test test, Throwable t) {
+        }
+
+        public void addFailure(Test test, AssertionFailedError t) {
+        }
+
+        public void endTest(Test test) {
+        }
+
+        public void startTest(Test test) {
+            if (test instanceof TestCase) {
+                testNames.add(((TestCase) test).getName());
+            } else if (test instanceof TestSuite) {
+                testNames.add(((TestSuite) test).getName());
+            }
+        }
+
+        public boolean saw(String testName) {
+            return testNames.contains(testName);
+        }
+    }
+
+    private static class StubContext extends MockContext {
+        private ClassLoader mClassLoader;
+
+        public StubContext(ClassLoader classLoader) {
+            this.mClassLoader = classLoader;
+        }
+
+        @Override
+        public ClassLoader getClassLoader() {
+            return mClassLoader;
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java b/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java
new file mode 100644
index 0000000..d9afd54
--- /dev/null
+++ b/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2008 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.test;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.test.mock.MockContext;
+import android.test.suitebuilder.ListTestCaseNames;
+import android.test.suitebuilder.ListTestCaseNames.TestDescriptor;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+/**
+ * Tests for {@link InstrumentationTestRunner}
+ */
+@SmallTest
+public class InstrumentationTestRunnerTest extends TestCase {
+    private StubInstrumentationTestRunner mInstrumentationTestRunner;
+    private StubAndroidTestRunner mStubAndroidTestRunner;
+    private String mTargetContextPackageName;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mStubAndroidTestRunner = new StubAndroidTestRunner();
+        mTargetContextPackageName = "android.test.suitebuilder.examples";
+        mInstrumentationTestRunner = new StubInstrumentationTestRunner(
+                new StubContext("com.google.foo.tests"),
+                new StubContext(mTargetContextPackageName), mStubAndroidTestRunner);
+    }
+
+    public void testOverrideTestToRunWithClassArgument() throws Exception {
+        String expectedTestClassName = PlaceHolderTest.class.getName();
+        mInstrumentationTestRunner.onCreate(createBundle(
+                InstrumentationTestRunner.ARGUMENT_TEST_CLASS, expectedTestClassName));
+
+        assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, "testPlaceHolder");
+    }
+
+    public void testOverrideTestToRunWithClassAndMethodArgument() throws Exception {
+        String expectedTestClassName = PlaceHolderTest.class.getName();
+        String expectedTestMethodName = "testPlaceHolder";
+        String classAndMethod = expectedTestClassName + "#" + expectedTestMethodName;
+        mInstrumentationTestRunner.onCreate(createBundle(
+                InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod));
+
+        assertTestRunnerCalledWithExpectedParameters(expectedTestClassName,
+                expectedTestMethodName);
+    }
+
+    public void testUseSelfAsTestSuiteProviderWhenNoMetaDataOrClassArgument() throws Exception {
+        TestSuite testSuite = new TestSuite();
+        testSuite.addTestSuite(PlaceHolderTest.class);
+        mInstrumentationTestRunner.setAllTestsSuite(testSuite);
+        mInstrumentationTestRunner.onCreate(null);
+        assertTestRunnerCalledWithExpectedParameters(
+                PlaceHolderTest.class.getName(), "testPlaceHolder");
+    }
+    
+    public void testMultipleTestClass() throws Exception {
+        String classArg = PlaceHolderTest.class.getName() + "," + 
+            PlaceHolderTest2.class.getName();
+        mInstrumentationTestRunner.onCreate(createBundle(
+                InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classArg));
+        
+        Test test = mStubAndroidTestRunner.getTest();
+
+        assertContentsInOrder(ListTestCaseNames.getTestNames((TestSuite) test),
+            new TestDescriptor(PlaceHolderTest.class.getName(), "testPlaceHolder"), 
+            new TestDescriptor(PlaceHolderTest2.class.getName(), "testPlaceHolder2"));
+        
+    }
+
+    public void testDelayParameter() throws Exception {
+        int delayMsec = 1000;
+        Bundle args = new Bundle();
+        args.putInt(InstrumentationTestRunner.ARGUMENT_DELAY_MSEC, delayMsec);
+        args.putString(InstrumentationTestRunner.ARGUMENT_TEST_CLASS,
+                PlaceHolderTest.class.getName() + "," +
+                PlaceHolderTest2.class.getName());
+        mInstrumentationTestRunner.onCreate(args);
+        Thread t = new Thread() { public void run() { mInstrumentationTestRunner.onStart(); } };
+
+        // Should delay three times: before, between, and after the two tests.
+        long beforeTest = System.currentTimeMillis();
+        t.start();
+        t.join();
+        assertTrue(System.currentTimeMillis() > beforeTest + delayMsec * 3);
+        assertTrue(mInstrumentationTestRunner.isStarted());
+        assertTrue(mInstrumentationTestRunner.isFinished());
+        assertTrue(mStubAndroidTestRunner.isRun());
+    }
+
+    private void assertContentsInOrder(List<TestDescriptor> actual, TestDescriptor... source) {
+        TestDescriptor[] clonedSource = source.clone();
+        assertEquals("Unexpected number of items.", clonedSource.length, actual.size());
+        for (int i = 0; i < actual.size(); i++) {
+            TestDescriptor actualItem = actual.get(i);
+            TestDescriptor sourceItem = clonedSource[i];
+            assertEquals("Unexpected item. Index: " + i, sourceItem, actualItem);
+        }
+    }
+
+    private void assertTestRunnerCalledWithExpectedParameters(
+            String expectedTestClassName, String expectedTestMethodName) {
+        Test test = mStubAndroidTestRunner.getTest();
+        assertContentsInOrder(ListTestCaseNames.getTestNames((TestSuite) test),
+                new TestDescriptor(expectedTestClassName, expectedTestMethodName));  
+        assertTrue(mInstrumentationTestRunner.isStarted());
+        assertFalse(mInstrumentationTestRunner.isFinished());
+    }
+
+    private Bundle createBundle(String key, String value) {
+        Bundle bundle = new Bundle();
+        bundle.putString(key, value);
+        return bundle;
+    }
+
+    private static class StubInstrumentationTestRunner extends InstrumentationTestRunner {
+        private Context mContext;
+        private Context mTargetContext;
+        private boolean mStarted;
+        private boolean mFinished;
+        private AndroidTestRunner mAndroidTestRunner;
+        private TestSuite mTestSuite;
+        private TestSuite mDefaultTestSuite;
+        private String mPackageNameForDefaultTests;
+
+        public StubInstrumentationTestRunner(Context context, Context targetContext,
+                AndroidTestRunner androidTestRunner) {
+            this.mContext = context;
+            this.mTargetContext = targetContext;
+            this.mAndroidTestRunner = androidTestRunner;
+        }
+
+        public Context getContext() {
+            return mContext;
+        }
+
+        public TestSuite getAllTests() {
+            return mTestSuite;
+        }
+
+        public Context getTargetContext() {
+            return mTargetContext;
+        }
+
+        protected AndroidTestRunner getAndroidTestRunner() {
+            return mAndroidTestRunner;
+        }
+
+        public void start() {
+            mStarted = true;
+        }
+
+        public void finish(int resultCode, Bundle results) {
+            mFinished = true;
+        }
+
+        public boolean isStarted() {
+            return mStarted;
+        }
+
+        public boolean isFinished() {
+            return mFinished;
+        }
+
+        public void setAllTestsSuite(TestSuite testSuite) {
+            mTestSuite = testSuite;
+        }
+        
+        public void setDefaultTestsSuite(TestSuite testSuite) {
+            mDefaultTestSuite = testSuite;
+        }
+
+        public String getPackageNameForDefaultTests() {
+            return mPackageNameForDefaultTests;
+        }
+    }
+
+    private static class StubContext extends MockContext {
+        private String mPackageName;
+
+        public StubContext(String packageName) {
+            this.mPackageName = packageName;
+        }
+
+        @Override
+        public String getPackageCodePath() {
+            return mPackageName;
+        }
+
+        @Override
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        @Override
+        public ClassLoader getClassLoader() {
+            return getClass().getClassLoader();
+        }
+    }
+
+    private static class StubAndroidTestRunner extends AndroidTestRunner {
+        private Test mTest;
+        private boolean mRun;
+
+        public boolean isRun() {
+            return mRun;
+        }
+
+        public void setTest(Test test) {
+            super.setTest(test);
+            mTest = test;
+        }
+
+        public Test getTest() {
+            return mTest;
+        }
+
+        public void runTest() {
+            super.runTest();
+            mRun = true;
+        }
+    }
+
+    /**
+     * Empty test used for validation
+     */
+    public static class PlaceHolderTest extends TestCase {
+
+        public PlaceHolderTest() {
+            super("testPlaceHolder");
+        }
+
+        public void testPlaceHolder() throws Exception {
+
+        }
+    }
+    
+    /**
+     * Empty test used for validation
+     */
+    public static class PlaceHolderTest2 extends TestCase {
+
+        public PlaceHolderTest2() {
+            super("testPlaceHolder2");
+        }
+
+        public void testPlaceHolder2() throws Exception {
+
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/StubTestBrowserActivity.java b/tests/CoreTests/android/test/StubTestBrowserActivity.java
new file mode 100644
index 0000000..97ed3ce
--- /dev/null
+++ b/tests/CoreTests/android/test/StubTestBrowserActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import junit.framework.TestSuite;
+
+public class StubTestBrowserActivity extends TestBrowserActivity {
+
+    private static TestSuite mTestSuite;
+
+    static void setTopTestSuite(TestSuite testSuite) {
+        mTestSuite = testSuite;
+    }
+
+    @Override
+    public TestSuite getTopTestSuite() {
+        return mTestSuite;
+    }
+}
diff --git a/tests/CoreTests/android/test/TestBrowserActivityTest.java b/tests/CoreTests/android/test/TestBrowserActivityTest.java
new file mode 100644
index 0000000..6afbe37
--- /dev/null
+++ b/tests/CoreTests/android/test/TestBrowserActivityTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.view.IWindowManager;
+import android.widget.ListView;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+public class TestBrowserActivityTest extends InstrumentationTestCase {
+
+    private TestBrowserActivity mTestBrowserActivity;
+    private StubTestBrowserController mTestBrowserController;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        StubTestBrowserActivity.setTopTestSuite(null);
+        mTestBrowserController = new StubTestBrowserController();
+        ServiceLocator.setTestBrowserController(mTestBrowserController);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mTestBrowserActivity != null) {
+            mTestBrowserActivity.finish();
+        }
+        mTestBrowserActivity = null;
+        super.tearDown();
+    }
+
+    public void testEmptyListContent() throws Exception {
+        StubTestBrowserActivity.setTopTestSuite(new TestSuite());
+
+        mTestBrowserActivity = createActivity();
+
+        ListView listView = getListView();
+        // There is always an item on the list for running all tests.
+        assertEquals("Unexpected number of items on list view.", 1, listView.getCount());
+
+        assertEquals("Stubbed Test Browser", mTestBrowserActivity.getTitle().toString());
+    }
+
+    public void testOneListContent() throws Exception {
+        List<String> testCaseNames = Lists.newArrayList("AllTests");
+        StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames));
+
+        mTestBrowserActivity = createActivity();
+
+        ListView listView = getListView();
+        assertListViewContents(testCaseNames, listView);
+    }
+
+    public void testListWithTestCases() throws Exception {
+        List<String> testCaseNames = Lists.newArrayList("AllTests", "Apples", "Bananas", "Oranges");
+        StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames));
+
+        mTestBrowserActivity = createActivity();
+
+        ListView listView = getListView();
+        assertListViewContents(testCaseNames, listView);
+    }
+
+    public void testListWithTestSuite() throws Exception {
+        List<String> testCaseNames = Lists.newArrayList(OneTestTestCase.class.getSimpleName());
+        StubTestBrowserActivity.setTopTestSuite(new OneTestInTestSuite());
+
+        mTestBrowserActivity = createActivity();
+
+        ListView listView = getListView();
+        assertListViewContents(testCaseNames, listView);
+    }
+
+    public void testSelectATestCase() throws Exception {
+        List<String> testCaseNames = Lists.newArrayList("AllTests");
+        TestSuite testSuite = createTestSuite(testCaseNames);
+        StubTestBrowserActivity.setTopTestSuite(testSuite);
+
+        mTestBrowserController.setTestCase(OneTestTestCase.class);
+        mTestBrowserActivity = createActivity();
+
+        Instrumentation.ActivityMonitor activityMonitor = getInstrumentation().addMonitor(
+                TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME, null, false);
+        try {
+            assertEquals(0, activityMonitor.getHits());
+
+            ListView listView = getListView();
+            int invokedTestCaseIndex = 0;
+            listView.performItemClick(listView, invokedTestCaseIndex, 0);
+
+            Activity activity = activityMonitor.waitForActivityWithTimeout(2000);
+            assertNotNull(activity);
+            try {
+                assertEquals(1, activityMonitor.getHits());
+                assertEquals(invokedTestCaseIndex, mTestBrowserController.getLastPosition());
+            } finally {
+                activity.finish();
+            }
+        } finally {
+            getInstrumentation().removeMonitor(activityMonitor);
+        }
+    }
+
+    public void testCreateFromIntentWithOneTest() throws Exception {
+        List<String> testCaseNames = Lists.newArrayList("testOne");
+
+        mTestBrowserActivity = launchTestBrowserActivity(new TestSuite(OneTestTestCase.class));
+
+        ListView listView = getListView();
+        assertListViewContents(testCaseNames, listView);
+    }
+
+    public void testUpdateListOnStart() throws Exception {
+        StubTestBrowserActivity.setTopTestSuite(new TestSuite());
+
+        mTestBrowserActivity = createActivity();
+
+        ListView listView = getListView();
+        assertEquals("Unexpected number of items on list view.", 1, listView.getCount());
+
+        List<String> testCaseNames = Lists.newArrayList("AllTests");
+        StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames));
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            public void run() {
+                ((StubTestBrowserActivity) mTestBrowserActivity).onStart();
+            }
+        });
+
+        listView = getListView();
+        assertListViewContents(testCaseNames, listView);
+    }
+
+    public void testTitleHasTestSuiteName() throws Exception {
+        final String testSuiteName = "com.android.TestSuite";
+        StubTestBrowserActivity.setTopTestSuite(new TestSuite(testSuiteName));
+
+        mTestBrowserActivity = createActivity();
+
+        assertEquals("TestSuite", mTestBrowserActivity.getTitle().toString());
+    }
+    
+    private TestSuite createTestSuite(List<String> testCaseNames) {
+        return createTestSuite(testCaseNames.toArray(new String[testCaseNames.size()]));
+    }
+
+    private TestSuite createTestSuite(String... testCaseNames) {
+        TestSuite testSuite = new TestSuite();
+        for (String testCaseName : testCaseNames) {
+            testSuite.addTest(new FakeTestCase(testCaseName));
+        }
+
+        return testSuite;
+    }
+
+    public static class FakeTestCase extends TestCase {
+        public FakeTestCase(String name) {
+            super(name);
+        }
+    }
+
+    public static class OneTestTestCase extends TestCase {
+        public void testOne() throws Exception {
+        }
+    }
+
+    public static class OneTestInTestSuite extends TestSuite {
+        public static Test suite() {
+            TestSuite suite = new TestSuite(OneTestInTestSuite.class.getName());
+            suite.addTestSuite(OneTestTestCase.class);
+            return suite;
+        }
+    }
+
+    private void assertListViewContents(List<String> expectedTestCaseNames, ListView listView) {
+        assertEquals("Run All", listView.getItemAtPosition(0).toString());
+        assertEquals("Unexpected number of items on list view.",
+                expectedTestCaseNames.size() + 1, listView.getCount());
+        for (int i = 0; i < expectedTestCaseNames.size(); i++) {
+            String expectedTestCaseName = expectedTestCaseNames.get(i);
+            String actualTestCaseName = listView.getItemAtPosition(i + 1).toString();
+            assertEquals("Unexpected test case name. Index: " + i,
+                    expectedTestCaseName, actualTestCaseName);
+        }
+    }
+
+    private ListView getListView() {
+        return mTestBrowserActivity.getListView();
+    }
+
+    private TestBrowserActivity createActivity() throws RemoteException {
+        return launchActivity("android.test", StubTestBrowserActivity.class, null);
+    }
+
+    private Intent createIntent(TestSuite testSuite) {
+        Intent intent = new Intent(Intent.ACTION_RUN);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        String className = StubTestBrowserActivity.class.getName();
+        String packageName = className.substring(0, className.lastIndexOf("."));
+        intent.setClassName(packageName, className);
+        intent.setData(Uri.parse(testSuite.getName()));
+        return intent;
+    }
+
+    private TestBrowserActivity launchTestBrowserActivity(TestSuite testSuite)
+            throws RemoteException {
+        getInstrumentation().setInTouchMode(false);
+
+        TestBrowserActivity activity =
+                (TestBrowserActivity) getInstrumentation().startActivitySync(
+                        createIntent(testSuite));
+        getInstrumentation().waitForIdleSync();
+        return activity;
+    }
+
+    private static class StubTestBrowserController extends TestBrowserControllerImpl {
+        private int mPosition;
+        private Class<? extends TestCase> mTestCaseClass;
+
+        public Intent getIntentForTestAt(int position) {
+            mPosition = position;
+
+            Intent intent = new Intent();
+            intent.setAction(Intent.ACTION_RUN);
+
+            String className = TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME;
+            String testName = mTestCaseClass.getClass().getName();
+
+            String packageName = className.substring(0, className.lastIndexOf("."));
+            intent.setClassName(packageName, className);
+            intent.setData(Uri.parse(testName));
+
+            return intent;
+        }
+
+        public void setTestCase(Class<? extends TestCase> testCaseClass) {
+            mTestCaseClass = testCaseClass;
+        }
+
+        public int getLastPosition() {
+            return mPosition;
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/TestBrowserControllerImplTest.java b/tests/CoreTests/android/test/TestBrowserControllerImplTest.java
new file mode 100644
index 0000000..1315606
--- /dev/null
+++ b/tests/CoreTests/android/test/TestBrowserControllerImplTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import android.content.Intent;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class TestBrowserControllerImplTest extends TestCase {
+    private TestBrowserControllerImpl mTestBrowserController;
+    private TestBrowserViewStub mTestBrowserView;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTestBrowserController = new TestBrowserControllerImpl();
+        mTestBrowserView = new TestBrowserViewStub();
+        mTestBrowserController.registerView(mTestBrowserView);
+    }
+
+    public void testSetTestSuite() throws Exception {
+        TestSuite testSuite = new TestSuite();
+        testSuite.addTestSuite(DummyTestCase.class);
+
+        mTestBrowserController.setTestSuite(testSuite);
+
+        verifyTestNames(Arrays.asList("Run All", DummyTestCase.class.getSimpleName()),
+                mTestBrowserView.getTestNames());
+    }
+
+    private static void verifyTestNames(List<String> expectedTestNames,
+            List<String> actualTestNames) {
+        assertEquals(expectedTestNames.size(), actualTestNames.size());
+
+        // We use endsWith instead of equals because the return value of
+        // class.getSimpleName(), when called on an inner class, varies
+        // from one vm to another.
+        // This allows the test to pass in multiple environments.
+        for (int i = 0; i < expectedTestNames.size(); i++) {
+            assertTrue(actualTestNames.get(i).endsWith(expectedTestNames.get(i)));
+        }
+    }
+
+    public void testGetIntentForTestSuite() throws Exception {
+        TestSuite testSuite = new TestSuite();
+        testSuite.addTestSuite(DummyTestCase.class);
+
+        String targetBrowserActvityClassName = "com.android.bogus.DummyActivity";
+        String expectedTargetPackageName = "com.android.bogus";
+        mTestBrowserController.setTargetBrowserActivityClassName(targetBrowserActvityClassName);
+        mTestBrowserController.setTestSuite(testSuite);
+        mTestBrowserController.setTargetPackageName(expectedTargetPackageName);
+        Intent intent = mTestBrowserController.getIntentForTestAt(1);
+        verifyIntent(intent, DummyTestCase.class, expectedTargetPackageName);
+        assertEquals(targetBrowserActvityClassName, intent.getComponent().getClassName());
+    }
+
+    public void testGetIntentForTestCase() throws Exception {
+        TestSuite testSuite = new TestSuite();
+        testSuite.addTest(new DummyTestCase());
+
+        mTestBrowserController.setTestSuite(testSuite);
+        Intent intent = mTestBrowserController.getIntentForTestAt(1);
+        verifyIntent(intent, DummyTestCase.class, "com.android.testharness");
+        assertEquals(TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME,
+                intent.getComponent().getClassName());
+        assertEquals("testDummyTest",
+                intent.getStringExtra(TestBrowserController.BUNDLE_EXTRA_TEST_METHOD_NAME));
+    }
+
+    public void testGetIntentForRunAll() throws Exception {
+        TestSuite testSuite = new DummyTestSuite();
+        testSuite.addTestSuite(DummyTestCase.class);
+
+        mTestBrowserController.setTestSuite(testSuite);
+        Intent intent = mTestBrowserController.getIntentForTestAt(0);
+        verifyIntent(intent, DummyTestSuite.class, "com.android.testharness");
+    }
+
+    private static void verifyIntent(Intent intent, Class testClass, String expectedPackageName) {
+        assertEquals(Intent.ACTION_RUN, intent.getAction());
+        assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK,
+                intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK);
+        assertEquals(Intent.FLAG_ACTIVITY_MULTIPLE_TASK,
+                intent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+        assertEquals(testClass.getName(), intent.getData().toString());
+        assertEquals(expectedPackageName, intent.getComponent().getPackageName());
+    }
+
+    private static class DummyTestSuite extends TestSuite {
+        private DummyTestSuite() {
+            super(DummyTestSuite.class.getName());
+        }
+    }
+
+    private static class DummyTestCase extends TestCase {
+        private DummyTestCase() {
+            super("testDummyTest");
+        }
+
+        public void testDummyTest() throws Exception {
+        }
+    }
+
+    private class TestBrowserViewStub implements TestBrowserView {
+        private List<String> mTestNames;
+
+        public void setTestNames(List<String> testNames) {
+            mTestNames = testNames;
+        }
+
+        public List<String> getTestNames() {
+            return mTestNames;
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/TestBrowserTests.java b/tests/CoreTests/android/test/TestBrowserTests.java
new file mode 100644
index 0000000..535e2f8
--- /dev/null
+++ b/tests/CoreTests/android/test/TestBrowserTests.java
@@ -0,0 +1,22 @@
+// Copyright 2007 The Android Open Source Project
+
+
+package android.test;
+
+import junit.framework.TestSuite;
+
+public class TestBrowserTests extends TestBrowserActivity {
+
+    @Override
+    public TestSuite getTopTestSuite() {
+        return suite();
+    }
+
+    public static TestSuite suite() {
+        TestSuite testSuite = new TestSuite(TestBrowserTests.class.getName());
+        testSuite.addTestSuite(TestBrowserControllerImplTest.class);
+        testSuite.addTestSuite(TestCaseUtilTest.class);
+
+        return testSuite;
+    }
+}
diff --git a/tests/CoreTests/android/test/TestCaseUtilTest.java b/tests/CoreTests/android/test/TestCaseUtilTest.java
new file mode 100644
index 0000000..bc6fa92
--- /dev/null
+++ b/tests/CoreTests/android/test/TestCaseUtilTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 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.test;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+public class TestCaseUtilTest extends TestCase {
+
+    public void testGetTestCaseNamesForTestSuiteWithSuiteMethod() throws Exception {
+        TestSuite testSuite = new TwoTestsInTestSuite();
+
+        List<String> testCaseNames = TestCaseUtil.getTestCaseNames(testSuite, false);
+
+        assertEquals(2, testCaseNames.size());
+        assertTrue(testCaseNames.get(0).endsWith("OneTestTestCase"));
+        assertTrue(testCaseNames.get(1).endsWith("OneTestTestSuite"));
+    }
+    
+    public void testGetTestCaseNamesForTestCaseWithSuiteMethod() throws Exception {
+        TestCase testCase = new OneTestTestCaseWithSuite();
+
+        List<String> testCaseNames = TestCaseUtil.getTestCaseNames(testCase, false);
+
+        assertEquals(1, testCaseNames.size());
+        assertTrue(testCaseNames.get(0).endsWith("testOne"));
+    }
+
+    public void testCreateTestForTestCase() throws Exception {
+        Test test = TestCaseUtil.createTestSuite(OneTestTestCase.class);
+        assertEquals(1, test.countTestCases());
+    }
+    
+    public void testCreateTestForTestSuiteWithSuiteMethod() throws Exception {
+        Test test = TestCaseUtil.createTestSuite(TwoTestsInTestSuite.class);
+        assertEquals(2, test.countTestCases());
+    }
+
+    public void testCreateTestForTestCaseWithSuiteMethod() throws Exception {
+        Test test = TestCaseUtil.createTestSuite(OneTestTestCaseWithSuite.class);
+        assertEquals(1, test.countTestCases());
+    }
+    
+    public void testReturnEmptyStringForTestSuiteWithNoName() throws Exception {
+        assertEquals("", TestCaseUtil.getTestName(new TestSuite()));
+    }
+
+    public static class OneTestTestCase extends TestCase {
+        public void testOne() throws Exception {
+        }
+    }
+
+    public static class OneTestTestCaseWithSuite extends TestCase {
+        public static Test suite()  {
+            TestCase testCase = new OneTestTestCase();
+            testCase.setName("testOne");
+            return testCase;
+        }
+
+        public void testOne() throws Exception {
+        }
+
+        public void testTwo() throws Exception {
+        }
+    }
+
+    public static class OneTestTestSuite {
+        public static Test suite() {
+            TestSuite suite = new TestSuite(OneTestTestSuite.class.getName());
+            suite.addTestSuite(OneTestTestCase.class);
+            return suite;
+        }
+    }
+
+    public static class TwoTestsInTestSuite extends TestSuite {
+        public static Test suite() {
+            TestSuite suite = new TestSuite(TwoTestsInTestSuite.class.getName());
+            suite.addTestSuite(OneTestTestCase.class);
+            suite.addTest(OneTestTestSuite.suite());
+            return suite;
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java b/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java
new file mode 100644
index 0000000..0f73e89
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Method;
+
+public class AssignableFromTest extends TestCase {
+    private AssignableFrom assignableFrom;
+
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        assignableFrom = new AssignableFrom(Animal.class);
+    }
+
+    public void testSelfIsAssignable() throws Exception {
+        assertTrue(assignableFrom.apply(testMethodFor(Animal.class)));
+    }
+
+    public void testSubclassesAreAssignable() throws Exception {
+        assertTrue(assignableFrom.apply(testMethodFor(Mammal.class)));
+        assertTrue(assignableFrom.apply(testMethodFor(Human.class)));
+    }
+
+    public void testNotAssignable() throws Exception {
+        assertFalse(assignableFrom.apply(testMethodFor(Pencil.class)));
+    }
+
+    public void testImplementorsAreAssignable() throws Exception {
+        assignableFrom = new AssignableFrom(WritingInstrument.class);
+
+        assertTrue(assignableFrom.apply(testMethodFor(Pencil.class)));
+        assertTrue(assignableFrom.apply(testMethodFor(Pen.class)));
+    }
+
+    private TestMethod testMethodFor(Class<? extends TestCase> aClass)
+            throws NoSuchMethodException {
+        Method method = aClass.getMethod("testX");
+        return new TestMethod(method, aClass);
+    }
+
+    private class Animal extends TestCase {
+        public void testX() {
+        }
+    }
+
+    private class Mammal extends Animal {
+        public void testX() {
+        }
+    }
+
+    private class Human extends Mammal {
+        public void testX() {
+        }
+    }
+
+    private interface WritingInstrument {
+    }
+
+    private class Pencil extends TestCase implements WritingInstrument {
+        public void testX() {
+        }
+    }
+
+    private class Pen extends TestCase implements WritingInstrument {
+        public void testX() {
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
new file mode 100644
index 0000000..1872803
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder;
+
+import static android.test.suitebuilder.ListTestCaseNames.getTestCaseNames;
+import android.test.suitebuilder.examples.OuterTest;
+import android.test.suitebuilder.examples.instrumentation.InstrumentationTest;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class InstrumentationTestSuiteBuilderTest extends TestCase {
+
+    private InstrumentationTestSuiteBuilder instrumentationTestSuiteBuilder;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        instrumentationTestSuiteBuilder = new InstrumentationTestSuiteBuilder(getClass());
+    }
+
+    public void testShouldIncludeIntrumentationTests() throws Exception {
+        instrumentationTestSuiteBuilder.includePackages(packageFor(InstrumentationTest.class));
+
+        SuiteExecutionRecorder recorder = runSuite(instrumentationTestSuiteBuilder);
+
+        assertEquals(1, recorder.testsSeen.size());
+        assertTrue(recorder.saw("InstrumentationTest.testInstrumentation"));
+    }
+
+    public void testShouldOnlyIncludeIntrumentationTests() throws Exception {
+        TestSuite testSuite = new OuterTest()
+                .buildTestsUnderHereWith(instrumentationTestSuiteBuilder);
+        List<String> testCaseNames = getTestCaseNames(testSuite);
+        assertEquals(1, testCaseNames.size());
+        assertEquals("testInstrumentation", testCaseNames.get(0));
+    }
+
+    private static String packageFor(Class clazz) {
+        String className = clazz.getName();
+        return className.substring(0, className.lastIndexOf('.'));
+    }
+
+    private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) {
+        TestSuite suite = builder.build();
+        SuiteExecutionRecorder recorder = new SuiteExecutionRecorder();
+        TestResult result = new TestResult();
+        result.addListener(recorder);
+        suite.run(result);
+        return recorder;
+    }
+
+    private class SuiteExecutionRecorder implements TestListener {
+
+        private Set<String> failures = new HashSet<String>();
+        private Set<String> errors = new HashSet<String>();
+        private Set<String> testsSeen = new HashSet<String>();
+
+        public void addError(Test test, Throwable t) {
+            errors.add(testName(test));
+        }
+
+        public void addFailure(Test test, AssertionFailedError t) {
+            failures.add(testName(test));
+        }
+
+        public void endTest(Test test) {
+        }
+
+        public void startTest(Test test) {
+            testsSeen.add(testName(test));
+        }
+
+        public boolean saw(String testName) {
+            return testsSeen.contains(testName);
+        }
+
+        public boolean failed(String testName) {
+            return failures.contains(testName);
+        }
+
+        public boolean errored(String testName) {
+            return errors.contains(testName);
+        }
+
+        public boolean passed(String testName) {
+            return saw(testName) && !failed(testName) && !errored(testName);
+        }
+
+        private String testName(Test test) {
+            TestCase testCase = (TestCase) test;
+            return testCase.getClass().getSimpleName() + "." + testCase.getName();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java b/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java
new file mode 100644
index 0000000..37ec328
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ListTestCaseNames {
+    public static List<String> getTestCaseNames(TestSuite suite) {
+        // TODO: deprecate this method and move all callers to use getTestNames
+        List<Test> tests = Collections.<Test>list(suite.tests());
+        ArrayList<String> testCaseNames = new ArrayList<String>();
+        for (Test test : tests) {
+            if (test instanceof TestCase) {
+                testCaseNames.add(((TestCase) test).getName());
+            } else if (test instanceof TestSuite) {
+                testCaseNames.addAll(getTestCaseNames((TestSuite) test));
+            }
+        }
+        return testCaseNames;
+    }
+    
+    /** 
+     * Returns a list of test class and method names for each TestCase in suite.  
+     */
+    public static List<TestDescriptor> getTestNames(TestSuite suite) {
+        List<Test> tests = Collections.<Test>list(suite.tests());
+        ArrayList<TestDescriptor> testNames = new ArrayList<TestDescriptor>();
+        for (Test test : tests) {
+            if (test instanceof TestCase) {
+                String className = test.getClass().getName();
+                String testName = ((TestCase) test).getName();
+                testNames.add(new TestDescriptor(className, testName));
+            } else if (test instanceof TestSuite) {
+                testNames.addAll(getTestNames((TestSuite) test));
+            }
+        }
+        return testNames;
+    }
+    
+    /**
+     * Data holder for test case info
+     */
+    public static class TestDescriptor {
+       private String mClassName;
+       private String mTestName;
+      
+       public TestDescriptor(String className, String testName) {
+           mClassName = className;
+           mTestName = testName;
+       }
+       
+       public String getClassName() {
+           return mClassName;
+       }
+       
+       public String getTestName() {
+           return mTestName;
+       }
+       
+       /**
+        * Override parent to do string-based class and test name comparison
+        */
+       @Override
+       public boolean equals(Object otherObj) {
+           if (otherObj instanceof TestDescriptor) {
+               TestDescriptor otherDesc = (TestDescriptor)otherObj;
+               return otherDesc.getClassName().equals(this.getClassName()) && 
+                      otherDesc.getTestName().equals(this.getTestName());
+               
+           }
+           return false;
+       }
+       
+       /**
+        * Override parent to return a more user-friendly display string
+        */
+       @Override
+       public String toString() {
+           return getClassName() + "#" + getTestName();
+       }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java
new file mode 100644
index 0000000..f817297
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+public class SmokeTestSuiteBuilderTest extends TestCase {
+
+    public void testShouldOnlyIncludeSmokeTests() throws Exception {
+        TestSuite testSuite = new SmokeTestSuiteBuilder(getClass())
+                .includeAllPackagesUnderHere().build();
+
+        List<String> testCaseNames = ListTestCaseNames.getTestCaseNames(testSuite);
+        assertEquals("Unexpected number of smoke tests.", 1, testCaseNames.size());
+        assertEquals("Unexpected test name", "testSmoke", testCaseNames.get(0));
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java
new file mode 100644
index 0000000..293c813
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder;
+
+import com.android.internal.util.Predicate;
+import static android.test.suitebuilder.ListTestCaseNames.getTestCaseNames;
+import android.test.suitebuilder.examples.OuterTest;
+import android.test.suitebuilder.examples.suppress.SuppressedTest;
+import android.test.suitebuilder.examples.error.ErrorTest;
+import android.test.suitebuilder.examples.error.FailingTest;
+import android.test.suitebuilder.examples.nested.Level1Test;
+import android.test.suitebuilder.examples.nested.nested.Level2Test;
+import android.test.suitebuilder.examples.simple.SimpleTest;
+import android.test.suitebuilder.examples.subclass.SubclassTest;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+public class TestSuiteBuilderTest extends TestCase {
+
+    private TestSuiteBuilder testSuiteBuilder;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        testSuiteBuilder = new TestSuiteBuilder(getClass());
+    }
+
+    public void testShouldRunSimpleTests() throws Exception {
+        testSuiteBuilder.includePackages(packageFor(SimpleTest.class));
+
+        SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+        assertTrue(recorder.passed("SimpleTest.testSimpleOne"));
+        assertTrue(recorder.passed("SimpleTest.testSimpleTwo"));
+        assertTrue(recorder.passed("AnotherSimpleTest.testAnotherOne"));
+    }
+
+    public void testShouldOnlyIncludeTestsThatSatisfyAllPredicates() throws Exception {
+        testSuiteBuilder.includePackages(packageFor(SimpleTest.class))
+                .addRequirements(testsWhoseNameContains("test"))
+                .addRequirements(testsWhoseNameContains("Simple"))
+                .addRequirements(testsWhoseNameContains("Two"));
+
+        SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+        assertTrue(recorder.passed("SimpleTest.testSimpleTwo"));
+    }
+
+    public void testShouldAddFailingTestsToSuite() throws Exception {
+        testSuiteBuilder.includePackages(packageFor(FailingTest.class));
+
+        SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+        assertTrue(recorder.failed("FailingTest.testFailOne"));
+        assertTrue(recorder.failed("FailingTest.testFailTwo"));
+    }
+
+    public void testShouldAddTestsWithErrorsToSuite() throws Exception {
+        testSuiteBuilder.includePackages(packageFor(ErrorTest.class));
+
+        SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+        assertTrue(recorder.errored("ErrorTest.testErrorOne"));
+        assertTrue(recorder.errored("ErrorTest.testErrorTwo"));
+    }
+
+    public void testShouldRunTestsInheritedFromSuperclass() throws Exception {
+        testSuiteBuilder.includePackages(packageFor(SubclassTest.class));
+
+        SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+        assertEquals(2, getTestCaseNames(testSuiteBuilder.build()).size());
+
+        assertTrue(recorder.passed("SubclassTest.testSubclass"));
+        assertTrue(recorder.passed("SubclassTest.testSuperclass"));
+        assertFalse(recorder.saw("SuperclassTest.testSuperclass"));
+    }
+
+    public void testShouldIncludeTestsInSubPackagesRecursively() throws Exception {
+        testSuiteBuilder.includePackages(packageFor(Level1Test.class));
+
+        SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+        assertTrue(recorder.passed("Level1Test.testLevel1"));
+        assertTrue(recorder.passed("Level2Test.testLevel2"));
+    }
+
+    public void testExcludePackage() throws Exception {
+        testSuiteBuilder.includePackages(packageFor(SimpleTest.class),
+                packageFor(Level1Test.class)).excludePackages(packageFor(Level2Test.class));
+
+        TestSuite testSuite = testSuiteBuilder.build();
+        assertContentsInOrder(getTestCaseNames(testSuite),
+                "testLevel1", "testAnotherOne", "testSimpleOne", "testSimpleTwo");
+    }
+
+    public void testShouldExcludeSuppressedTests() throws Exception {
+        testSuiteBuilder.includePackages(packageFor(SuppressedTest.class));
+        testSuiteBuilder.build();
+
+        SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+        assertEquals(1, recorder.testsSeen.size());
+        assertTrue(recorder.passed("PartiallySuppressedTest.testUnSuppressedMethod"));
+    }
+
+    /**
+     * This test calls {@link OuterTest#buildTestsUnderHereRecursively()} to control
+     * the packages under test. The call to {@link TestSuiteBuilder#includeAllPackagesUnderHere()}
+     * is made from there so that only return the example tests.
+     */
+    public void testIncludeAllPackagesUnderHere() throws Exception {
+
+        TestSuite testSuite = new OuterTest().buildTestsUnderHereRecursively();
+        assertContentsInOrder(getTestCaseNames(testSuite),
+                "testOuter", "testErrorOne", "testErrorTwo", "testFailOne", "testFailTwo",
+                "testInstrumentation", "testLevel1", "testLevel2", "testAnotherOne",
+                "testSimpleOne", "testSimpleTwo", "testNonSmoke", "testSmoke", "testSubclass",
+                "testSuperclass", "testUnSuppressedMethod");
+    }
+
+    private void assertContentsInOrder(List<String> actual, String... source) {
+        String[] clonedSource = source.clone();
+        assertEquals("Unexpected number of items.", clonedSource.length, actual.size());
+        for (int i = 0; i < actual.size(); i++) {
+            String actualItem = actual.get(i);
+            String sourceItem = clonedSource[i];
+            assertEquals("Unexpected item. Index: " + i, sourceItem, actualItem);
+        }
+    }
+
+    private static String packageFor(Class clazz) {
+        String className = clazz.getName();
+        return className.substring(0, className.lastIndexOf('.'));
+    }
+
+    private Predicate<TestMethod> testsWhoseNameContains(final String string) {
+        return new Predicate<TestMethod>() {
+            public boolean apply(TestMethod testMethod) {
+                return testMethod.getName().contains(string);
+            }
+        };
+    }
+
+    private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) {
+        TestSuite suite = builder.build();
+        SuiteExecutionRecorder recorder = new SuiteExecutionRecorder();
+        TestResult result = new TestResult();
+        result.addListener(recorder);
+        suite.run(result);
+        return recorder;
+    }
+
+    private class SuiteExecutionRecorder implements TestListener {
+
+        private Set<String> failures = new HashSet<String>();
+        private Set<String> errors = new HashSet<String>();
+        private Set<String> testsSeen = new HashSet<String>();
+
+        public void addError(Test test, Throwable t) {
+            errors.add(testName(test));
+        }
+
+        public void addFailure(Test test, AssertionFailedError t) {
+            failures.add(testName(test));
+        }
+
+        public void endTest(Test test) {
+        }
+
+        public void startTest(Test test) {
+            testsSeen.add(testName(test));
+        }
+
+        public boolean saw(String testName) {
+            return testsSeen.contains(testName);
+        }
+
+        public boolean failed(String testName) {
+            return failures.contains(testName);
+        }
+
+        public boolean errored(String testName) {
+            return errors.contains(testName);
+        }
+
+        public boolean passed(String testName) {
+            return saw(testName) && !failed(testName) && !errored(testName);
+        }
+
+        private String testName(Test test) {
+            TestCase testCase = (TestCase) test;
+            return testCase.getClass().getSimpleName() + "." + testCase.getName();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java
new file mode 100644
index 0000000..469938e
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder;
+
+import android.test.suitebuilder.examples.instrumentation.InstrumentationTest;
+
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class UnitTestSuiteBuilderTest extends TestCase {
+
+    private UnitTestSuiteBuilder unitTestSuiteBuilder;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        unitTestSuiteBuilder = new UnitTestSuiteBuilder(getClass());
+    }
+
+    public void testShouldExcludeIntrumentationTests() throws Exception {
+        unitTestSuiteBuilder.includePackages(packageFor(InstrumentationTest.class));
+
+        TestSuite testSuite = unitTestSuiteBuilder.build();
+        Assert.assertEquals(0, ListTestCaseNames.getTestCaseNames(testSuite).size());
+
+        SuiteExecutionRecorder recorder = runSuite(unitTestSuiteBuilder);
+
+        assertFalse(recorder.saw("InstrumentationTest.testInstrumentation"));
+        assertTrue(recorder.testsSeen.isEmpty());
+    }
+
+    private static String packageFor(Class clazz) {
+        String className = clazz.getName();
+        return className.substring(0, className.lastIndexOf('.'));
+    }
+
+    private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) {
+        TestSuite suite = builder.build();
+        SuiteExecutionRecorder recorder = new SuiteExecutionRecorder();
+        TestResult result = new TestResult();
+        result.addListener(recorder);
+        suite.run(result);
+        return recorder;
+    }
+
+    private class SuiteExecutionRecorder implements TestListener {
+
+        private Set<String> failures = new HashSet<String>();
+        private Set<String> errors = new HashSet<String>();
+        private Set<String> testsSeen = new HashSet<String>();
+
+        public void addError(Test test, Throwable t) {
+            errors.add(testName(test));
+        }
+
+        public void addFailure(Test test, AssertionFailedError t) {
+            failures.add(testName(test));
+        }
+
+        public void endTest(Test test) {
+        }
+
+        public void startTest(Test test) {
+            testsSeen.add(testName(test));
+        }
+
+        public boolean saw(String testName) {
+            return testsSeen.contains(testName);
+        }
+
+        public boolean failed(String testName) {
+            return failures.contains(testName);
+        }
+
+        public boolean errored(String testName) {
+            return errors.contains(testName);
+        }
+
+        public boolean passed(String testName) {
+            return saw(testName) && !failed(testName) && !errored(testName);
+        }
+
+        private String testName(Test test) {
+            TestCase testCase = (TestCase) test;
+            return testCase.getClass().getSimpleName() + "." + testCase.getName();
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java
new file mode 100644
index 0000000..edf067d
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.annotation;
+
+import android.test.suitebuilder.TestMethod;
+import junit.framework.TestCase;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+
+public class HasAnnotationTest extends TestCase {
+
+    public void testThatMethodWithAnnotationIsReportedAsBeingAnnotated() throws Exception {
+        assertTrue(hasExampleAnnotation(ClassWithAnnotation.class, "testWithAnnotation"));
+        assertTrue(hasExampleAnnotation(ClassWithoutAnnotation.class, "testWithAnnotation"));
+    }
+
+    public void testThatMethodWithOutAnnotationIsNotReportedAsBeingAnnotated() throws Exception {
+        assertFalse(hasExampleAnnotation(ClassWithoutAnnotation.class, "testWithoutAnnotation"));
+    }
+
+    public void testThatClassAnnotatioCausesAllMethodsToBeReportedAsBeingAnnotated()
+            throws Exception {
+        assertTrue(hasExampleAnnotation(ClassWithAnnotation.class, "testWithoutAnnotation"));
+    }
+
+    private boolean hasExampleAnnotation(Class<? extends TestCase> aClass, String methodName)
+            throws NoSuchMethodException {
+        Method method = aClass.getMethod(methodName);
+        TestMethod testMethod = new TestMethod(method, aClass);
+        return new HasAnnotation(Example.class).apply(testMethod);
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.TYPE, ElementType.METHOD})
+    public @interface Example {
+    }
+
+    @Example
+    static class ClassWithAnnotation extends TestCase {
+
+        @Example
+        public void testWithAnnotation() {
+        }
+
+        public void testWithoutAnnotation() {
+        }
+    }
+
+    static class ClassWithoutAnnotation extends TestCase {
+
+        @Example
+        public void testWithAnnotation() {
+        }
+
+        public void testWithoutAnnotation() {
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java
new file mode 100644
index 0000000..051ea54
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.annotation;
+
+import android.test.suitebuilder.TestMethod;
+import junit.framework.TestCase;
+
+import java.lang.reflect.Method;
+
+public class HasClassAnnotationTest extends TestCase {
+
+    public void testShouldTellIfParentClassHasSpecifiedClassification()
+            throws NoSuchMethodException {
+        assertTrue(classHasAnnotation(SmokeTestExample.class, Smoke.class));
+    }
+
+    public void testShouldTellIfParentClassDoesNotHaveSpecifiedClassification()
+            throws NoSuchMethodException {
+        assertFalse(classHasAnnotation(NonSmokeTestExample.class, Smoke.class));
+    }
+
+    private boolean classHasAnnotation(
+            Class<? extends TestCase> aClass,
+            Class<Smoke> expectedClassification) throws NoSuchMethodException {
+        Method method = aClass.getMethod("testSomeTest");
+
+        TestMethod testMethod = new TestMethod(method, aClass);
+        return new HasClassAnnotation(expectedClassification).apply(testMethod);
+    }
+
+    @Smoke
+    static class SmokeTestExample extends TestCase {
+
+        public void testSomeTest() {
+        }
+    }
+
+    static class NonSmokeTestExample extends TestCase {
+
+        public void testSomeTest() {
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java
new file mode 100644
index 0000000..c864e28
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.annotation;
+
+import android.test.suitebuilder.TestMethod;
+import junit.framework.TestCase;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+
+public class HasMethodAnnotationTest extends TestCase {
+
+    public void testMethodWithSpecifiedAttribute() throws Exception {
+        assertTrue(methodHasAnnotation(AnnotatedMethodExample.class,
+                "testThatIsAnnotated", Smoke.class));
+    }
+
+    public void testMethodWithoutSpecifiedAttribute() throws Exception {
+        assertFalse(methodHasAnnotation(AnnotatedMethodExample.class,
+                "testThatIsNotAnnotated", Smoke.class));
+    }
+
+    private boolean methodHasAnnotation(Class<? extends TestCase> aClass,
+            String methodName,
+            Class<? extends Annotation> expectedClassification
+    ) throws NoSuchMethodException {
+        Method method = aClass.getMethod(methodName);
+        TestMethod testMethod = new TestMethod(method, aClass);
+        return new HasMethodAnnotation(expectedClassification).apply(testMethod);
+    }
+
+    static class AnnotatedMethodExample extends TestCase {
+
+        @Smoke
+        public void testThatIsAnnotated() {
+        }
+
+        public void testThatIsNotAnnotated() {
+        }
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java b/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java
new file mode 100644
index 0000000..4659bf9
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples;
+
+import android.test.suitebuilder.TestSuiteBuilder;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class OuterTest extends TestCase {
+
+    public void testOuter() {
+        assertTrue(true);
+    }
+
+    public TestSuite buildTestsUnderHereRecursively() {
+        return buildTestsUnderHereWith(new TestSuiteBuilder(getClass()));
+    }
+
+    public TestSuite buildTestsUnderHereWith(TestSuiteBuilder testSuiteBuilder) {
+        return testSuiteBuilder.includeAllPackagesUnderHere().build();
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java b/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java
new file mode 100644
index 0000000..f1f6113
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.error;
+
+import junit.framework.TestCase;
+
+public class ErrorTest extends TestCase {
+
+    public void testErrorOne() throws Exception {
+        throw new RuntimeException("Expected");
+    }
+
+    public void testErrorTwo() throws Exception {
+        throw new RuntimeException("Expected");
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java b/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java
new file mode 100644
index 0000000..428fd23
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.error;
+
+import junit.framework.TestCase;
+
+public class FailingTest extends TestCase {
+
+    public void testFailOne() throws Exception {
+        fail("Expected");
+    }
+
+    public void testFailTwo() throws Exception {
+        fail("Expected");
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java b/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java
new file mode 100644
index 0000000..5158a90
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.instrumentation;
+
+import android.test.InstrumentationTestCase;
+
+public class InstrumentationTest extends InstrumentationTestCase {
+
+    public void testInstrumentation() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java b/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java
new file mode 100644
index 0000000..17d39d6
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.nested;
+
+import junit.framework.TestCase;
+
+public class Level1Test extends TestCase {
+
+    public void testLevel1() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java b/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java
new file mode 100644
index 0000000..6f0daca
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.nested.nested;
+
+import junit.framework.TestCase;
+
+public class Level2Test extends TestCase {
+
+    public void testLevel2() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java b/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java
new file mode 100644
index 0000000..0dfeda8
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.simple;
+
+import junit.framework.TestCase;
+
+public class AnotherSimpleTest extends TestCase {
+
+    public void testAnotherOne() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java b/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java
new file mode 100644
index 0000000..4dcac44
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.simple;
+
+import junit.framework.TestCase;
+
+public class SimpleTest extends TestCase {
+
+    public void testSimpleOne() throws Exception {
+        assertTrue(true);
+    }
+
+    public void testSimpleTwo() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java b/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java
new file mode 100644
index 0000000..1512ba7
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.smoke;
+
+import junit.framework.TestCase;
+
+public class NonSmokeTest extends TestCase {
+
+    public void testNonSmoke() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java b/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java
new file mode 100644
index 0000000..c3515df
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.smoke;
+
+import android.test.suitebuilder.annotation.Smoke;
+import junit.framework.TestCase;
+
+@Smoke
+public class SmokeTest extends TestCase {
+
+    public void testSmoke() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java
new file mode 100644
index 0000000..0ab8c72
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.subclass;
+
+public class SubclassTest extends SuperclassTest {
+
+    public void testSubclass() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java
new file mode 100644
index 0000000..05513c5
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.subclass;
+
+import junit.framework.TestCase;
+
+public abstract class SuperclassTest extends TestCase {
+
+    public void testSuperclass() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java b/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java
new file mode 100644
index 0000000..3ca0f70
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.suppress;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+import junit.framework.TestCase;
+
+public class PartiallySuppressedTest extends TestCase {
+
+    @Suppress
+    public void testSuppressedMethod() throws Exception {
+        assertTrue(true);
+    }
+
+    public void testUnSuppressedMethod() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java b/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java
new file mode 100644
index 0000000..c4e0e07
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 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.test.suitebuilder.examples.suppress;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+import junit.framework.TestCase;
+
+@Suppress
+public class SuppressedTest extends TestCase {
+
+    public void testSuppressedClass() throws Exception {
+        assertTrue(true);
+    }
+}
diff --git a/tests/CoreTests/android/util/DayOfMonthCursorTest.java b/tests/CoreTests/android/util/DayOfMonthCursorTest.java
new file mode 100644
index 0000000..4c5ad76
--- /dev/null
+++ b/tests/CoreTests/android/util/DayOfMonthCursorTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 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.util;
+
+import junit.framework.TestCase;
+
+import java.util.Calendar;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Unit tests for {@link DayOfMonthCursor}.
+ */
+public class DayOfMonthCursorTest extends TestCase {
+
+    @SmallTest
+    public void testMonthRows() {
+        DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+                Calendar.SEPTEMBER, 11, Calendar.SUNDAY);
+
+        assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+                mc.getDigitsForRow(0));
+        assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8},
+                mc.getDigitsForRow(1));
+        assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6},
+                mc.getDigitsForRow(5));
+    }
+
+    @SmallTest
+    public void testMoveLeft() {
+        DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+                Calendar.SEPTEMBER, 3, Calendar.SUNDAY);
+
+        assertEquals(Calendar.SEPTEMBER, mc.getMonth());
+        assertEquals(3, mc.getSelectedDayOfMonth());
+        assertEquals(1, mc.getSelectedRow());
+        assertEquals(1, mc.getSelectedColumn());
+
+        // move left, still same row
+        assertFalse(mc.left());
+        assertEquals(2, mc.getSelectedDayOfMonth());
+        assertEquals(1, mc.getSelectedRow());
+        assertEquals(0, mc.getSelectedColumn());
+
+        // wrap over to previous column, same month
+        assertFalse(mc.left());
+        assertEquals(1, mc.getSelectedDayOfMonth());
+        assertEquals(0, mc.getSelectedRow());
+        assertEquals(6, mc.getSelectedColumn());
+
+        // wrap to previous month
+        assertTrue(mc.left());
+        assertEquals(Calendar.AUGUST, mc.getMonth());
+        assertEquals(31, mc.getSelectedDayOfMonth());
+        assertEquals(4, mc.getSelectedRow());
+        assertEquals(5, mc.getSelectedColumn());
+    }
+
+    @SmallTest
+    public void testMoveRight() {
+        DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+                Calendar.SEPTEMBER, 28, Calendar.SUNDAY);
+
+        assertEquals(Calendar.SEPTEMBER, mc.getMonth());
+        assertEquals(28, mc.getSelectedDayOfMonth());
+        assertEquals(4, mc.getSelectedRow());
+        assertEquals(5, mc.getSelectedColumn());
+
+        // same row
+        assertFalse(mc.right());
+        assertEquals(29, mc.getSelectedDayOfMonth());
+        assertEquals(4, mc.getSelectedRow());
+        assertEquals(6, mc.getSelectedColumn());
+
+        // wrap to next column, same month
+        assertFalse(mc.right());
+        assertEquals(30, mc.getSelectedDayOfMonth());
+        assertEquals(5, mc.getSelectedRow());
+        assertEquals(0, mc.getSelectedColumn());
+
+        // next month
+        assertTrue(mc.right());
+        assertEquals(Calendar.OCTOBER, mc.getMonth());
+        assertEquals(1, mc.getSelectedDayOfMonth());
+        assertEquals(0, mc.getSelectedRow());
+        assertEquals(1, mc.getSelectedColumn());
+    }
+
+    @SmallTest
+    public void testMoveUp() {
+        DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+                Calendar.SEPTEMBER, 13, Calendar.SUNDAY);
+
+        assertEquals(Calendar.SEPTEMBER, mc.getMonth());
+        assertEquals(13, mc.getSelectedDayOfMonth());
+        assertEquals(2, mc.getSelectedRow());
+        assertEquals(4, mc.getSelectedColumn());
+
+        // up, same month
+        assertFalse(mc.up());
+        assertEquals(6, mc.getSelectedDayOfMonth());
+        assertEquals(1, mc.getSelectedRow());
+        assertEquals(4, mc.getSelectedColumn());
+
+        // up, flips back
+        assertTrue(mc.up());
+        assertEquals(Calendar.AUGUST, mc.getMonth());
+        assertEquals(30, mc.getSelectedDayOfMonth());
+        assertEquals(4, mc.getSelectedRow());
+        assertEquals(4, mc.getSelectedColumn());
+    }
+
+    @SmallTest
+    public void testMoveDown() {
+        DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+                Calendar.SEPTEMBER, 23, Calendar.SUNDAY);
+
+        assertEquals(Calendar.SEPTEMBER, mc.getMonth());
+        assertEquals(23, mc.getSelectedDayOfMonth());
+        assertEquals(4, mc.getSelectedRow());
+        assertEquals(0, mc.getSelectedColumn());
+
+        // down, same month
+        assertFalse(mc.down());
+        assertEquals(30, mc.getSelectedDayOfMonth());
+        assertEquals(5, mc.getSelectedRow());
+        assertEquals(0, mc.getSelectedColumn());
+
+        // down, next month
+        assertTrue(mc.down());
+        assertEquals(Calendar.OCTOBER, mc.getMonth());
+        assertEquals(7, mc.getSelectedDayOfMonth());
+        assertEquals(1, mc.getSelectedRow());
+        assertEquals(0, mc.getSelectedColumn());
+    }
+
+    private void assertArraysEqual(int[] expected, int[] actual) {
+        assertEquals("array length", expected.length, actual.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("index " + i,
+                    expected[i], actual[i]);
+        }
+    }
+}
diff --git a/tests/CoreTests/android/util/FloatMathTest.java b/tests/CoreTests/android/util/FloatMathTest.java
new file mode 100644
index 0000000..f479e2b
--- /dev/null
+++ b/tests/CoreTests/android/util/FloatMathTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 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.util;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class FloatMathTest extends TestCase {
+
+    @SmallTest
+    public void testSqrt() {
+        assertEquals(7, FloatMath.sqrt(49), 0);
+        assertEquals(10, FloatMath.sqrt(100), 0);
+        assertEquals(0, FloatMath.sqrt(0), 0);
+        assertEquals(1, FloatMath.sqrt(1), 0);
+    }
+
+    @SmallTest
+    public void testFloor() {
+        assertEquals(78, FloatMath.floor(78.89f), 0);
+        assertEquals(-79, FloatMath.floor(-78.89f), 0);
+    }
+
+    @SmallTest
+    public void testCeil() {
+        assertEquals(79, FloatMath.ceil(78.89f), 0);
+        assertEquals(-78, FloatMath.ceil(-78.89f), 0);
+    }
+
+    @SmallTest
+    public void testSin() {
+        assertEquals(0.0, FloatMath.sin(0), 0);
+        assertEquals(0.8414709848078965f, FloatMath.sin(1), 0);
+    }
+
+    @SmallTest
+    public void testCos() {
+        assertEquals(1.0f, FloatMath.cos(0), 0);
+        assertEquals(0.5403023058681398f, FloatMath.cos(1), 0);
+    }
+}
diff --git a/tests/CoreTests/android/util/MonthDisplayHelperTest.java b/tests/CoreTests/android/util/MonthDisplayHelperTest.java
new file mode 100644
index 0000000..5207ad9
--- /dev/null
+++ b/tests/CoreTests/android/util/MonthDisplayHelperTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2007 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.util;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.util.Calendar;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Unit tests for {@link MonthDisplayHelper}.
+ */
+public class MonthDisplayHelperTest extends TestCase {
+
+
+    @SmallTest
+    public void testFirstDayOfMonth() {
+
+        assertEquals("august 2007",
+                Calendar.WEDNESDAY,
+                new MonthDisplayHelper(2007, Calendar.AUGUST).getFirstDayOfMonth());
+
+        assertEquals("september, 2007",
+                Calendar.SATURDAY,
+                new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getFirstDayOfMonth());
+    }
+
+    @MediumTest
+    public void testNumberOfDaysInCurrentMonth() {
+        assertEquals(30,
+                new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getNumberOfDaysInMonth());
+    }
+
+    @SmallTest
+    public void testMonthRows() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER);
+
+        assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+                helper.getDigitsForRow(0));
+        assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8},
+                helper.getDigitsForRow(1));
+        assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6},
+                helper.getDigitsForRow(5));
+
+    }
+
+    @SmallTest
+    public void testMonthRowsWeekStartsMonday() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.SEPTEMBER, Calendar.MONDAY);
+
+        assertArraysEqual(new int[]{27, 28, 29, 30, 31, 1, 2},
+                helper.getDigitsForRow(0));
+        assertArraysEqual(new int[]{3, 4, 5, 6, 7, 8, 9},
+                helper.getDigitsForRow(1));
+        assertArraysEqual(new int[]{24, 25, 26, 27, 28, 29, 30},
+                helper.getDigitsForRow(4));
+        assertArraysEqual(new int[]{1, 2, 3, 4, 5, 6, 7},
+                helper.getDigitsForRow(5));
+    }
+
+    @SmallTest
+    public void testMonthRowsWeekStartsSaturday() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.SEPTEMBER, Calendar.SATURDAY);
+
+        assertArraysEqual(new int[]{1, 2, 3, 4, 5, 6, 7},
+                helper.getDigitsForRow(0));
+        assertArraysEqual(new int[]{8, 9, 10, 11, 12, 13, 14},
+                helper.getDigitsForRow(1));
+        assertArraysEqual(new int[]{29, 30, 1, 2, 3, 4, 5},
+                helper.getDigitsForRow(4));
+
+
+        helper = new MonthDisplayHelper(2007,
+                Calendar.AUGUST, Calendar.SATURDAY);
+
+        assertArraysEqual(new int[]{28, 29, 30, 31, 1, 2, 3},
+                helper.getDigitsForRow(0));
+        assertArraysEqual(new int[]{4, 5, 6, 7, 8, 9, 10},
+                helper.getDigitsForRow(1));
+        assertArraysEqual(new int[]{25, 26, 27, 28, 29, 30, 31},
+                helper.getDigitsForRow(4));
+    }
+
+    @SmallTest
+    public void testGetDayAt() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.SEPTEMBER, Calendar.SUNDAY);
+
+        assertEquals(26, helper.getDayAt(0, 0));
+        assertEquals(1, helper.getDayAt(0, 6));
+        assertEquals(17, helper.getDayAt(3, 1));
+        assertEquals(2, helper.getDayAt(5, 2));
+    }
+
+    @SmallTest
+    public void testPrevMonth() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.SEPTEMBER, Calendar.SUNDAY);
+
+        assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+                helper.getDigitsForRow(0));
+
+        helper.previousMonth();
+
+        assertEquals(Calendar.AUGUST, helper.getMonth());
+        assertArraysEqual(new int[]{29, 30, 31, 1, 2, 3, 4},
+                helper.getDigitsForRow(0));
+    }
+
+    @SmallTest
+    public void testPrevMonthRollOver() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.JANUARY);
+
+        helper.previousMonth();
+
+        assertEquals(2006, helper.getYear());
+        assertEquals(Calendar.DECEMBER, helper.getMonth());
+    }
+
+    @SmallTest
+    public void testNextMonth() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.AUGUST, Calendar.SUNDAY);
+
+        assertArraysEqual(new int[]{29, 30, 31, 1, 2, 3, 4},
+                helper.getDigitsForRow(0));
+
+        helper.nextMonth();
+
+        assertEquals(Calendar.SEPTEMBER, helper.getMonth());
+        assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+                helper.getDigitsForRow(0));
+    }
+
+    @SmallTest
+    public void testGetRowOf() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.AUGUST, Calendar.SUNDAY);
+
+        assertEquals(0, helper.getRowOf(2));
+        assertEquals(0, helper.getRowOf(4));
+        assertEquals(2, helper.getRowOf(12));
+        assertEquals(2, helper.getRowOf(18));
+        assertEquals(3, helper.getRowOf(19));
+    }
+
+    @SmallTest
+    public void testGetColumnOf() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.AUGUST, Calendar.SUNDAY);
+
+        assertEquals(3, helper.getColumnOf(1));
+        assertEquals(4, helper.getColumnOf(9));
+        assertEquals(5, helper.getColumnOf(17));
+        assertEquals(6, helper.getColumnOf(25));
+        assertEquals(0, helper.getColumnOf(26));
+    }
+
+    @SmallTest
+    public void testWithinCurrentMonth() {
+        MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+                Calendar.SEPTEMBER, Calendar.SUNDAY);
+
+        // out of bounds
+        assertFalse(helper.isWithinCurrentMonth(-1, 3));
+        assertFalse(helper.isWithinCurrentMonth(6, 3));
+        assertFalse(helper.isWithinCurrentMonth(2, -1));
+        assertFalse(helper.isWithinCurrentMonth(2, 7));
+
+        // last day of previous month
+        assertFalse(helper.isWithinCurrentMonth(0, 5));
+
+        // first day of next month
+        assertFalse(helper.isWithinCurrentMonth(5, 1));
+
+        // first day in month
+        assertTrue(helper.isWithinCurrentMonth(0, 6));
+
+        // last day in month
+        assertTrue(helper.isWithinCurrentMonth(5, 0));
+    }
+
+    private void assertArraysEqual(int[] expected, int[] actual) {
+        assertEquals("array length", expected.length, actual.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("index " + i,
+                    expected[i], actual[i]);
+        }
+    }
+
+}
diff --git a/tests/CoreTests/android/util/StateSetTest.java b/tests/CoreTests/android/util/StateSetTest.java
new file mode 100644
index 0000000..e481ce0
--- /dev/null
+++ b/tests/CoreTests/android/util/StateSetTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2007 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.util;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for {@link StateSet}
+ */
+
+public class StateSetTest extends TestCase {
+    
+    @SmallTest
+    public void testStateSetPositiveMatches() throws Exception {
+         int[] stateSpec = new int[2];
+         int[] stateSet = new int[3];
+         // Single states in both sets - match
+         stateSpec[0] = 1;
+         stateSet[0] = 1;
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Single states in both sets - non-match
+         stateSet[0] = 2;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Add another state to the spec which the stateSet doesn't match
+         stateSpec[1] = 2;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Add the missing matching element to the stateSet
+         stateSet[1] = 1;
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Add an irrelevent state to the stateSpec
+         stateSet[2] = 12345;
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+     }
+
+     @SmallTest
+     public void testStatesSetMatchMixEmUp() throws Exception {
+         int[] stateSpec = new int[2];
+         int[] stateSet = new int[2];
+         // One element in stateSpec which we must match and one which we must
+         // not match.  stateSet only contains the match.
+         stateSpec[0] = 1;
+         stateSpec[1] = -2;
+         stateSet[0] = 1;
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+         // stateSet now contains just the element we must not match
+         stateSet[0] = 2;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Add another matching state to the the stateSet.  We still fail
+         // because stateSet contains a must-not-match element
+         stateSet[1] = 1;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Switch the must-not-match element in stateSet with a don't care
+         stateSet[0] = 12345;
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+     }
+
+     @SmallTest
+     public void testStateSetNegativeMatches() throws Exception {
+         int[] stateSpec = new int[2];
+         int[] stateSet = new int[3];
+         // Single states in both sets - match
+         stateSpec[0] = -1;
+         stateSet[0] = 2;
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Add another arrelevent state to the stateSet
+         stateSet[1] = 12345;
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Single states in both sets - non-match
+         stateSet[0] = 1;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Add another state to the spec which the stateSet doesn't match
+         stateSpec[1] = -2;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         // Add an irrelevent state to the stateSet
+         stateSet[2] = 12345;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+     }
+
+     @SmallTest
+     public void testEmptySetMatchesNegtives() throws Exception {
+         int[] stateSpec = {-12345, -6789};
+         int[] stateSet = new int[0];
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+         int[] stateSet2 = {0};
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2));
+     }
+
+     @SmallTest
+     public void testEmptySetFailsPositives() throws Exception {
+         int[] stateSpec = {12345};
+         int[] stateSet = new int[0];
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         int[] stateSet2 = {0};
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet2));
+     }
+
+     @SmallTest
+     public void testEmptySetMatchesWildcard() throws Exception {
+         int[] stateSpec = StateSet.WILD_CARD;
+         int[] stateSet = new int[0];
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+         int[] stateSet2 = {0};
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2));
+     }
+
+     @SmallTest
+     public void testSingleStatePositiveMatches() throws Exception {
+         int[] stateSpec = new int[2];
+         int state;
+         //  match
+         stateSpec[0] = 1;
+         state = 1;
+         assertTrue(StateSet.stateSetMatches(stateSpec, state));
+         // non-match
+         state = 2;
+         assertFalse(StateSet.stateSetMatches(stateSpec, state));
+         // add irrelevant must-not-match
+         stateSpec[1] = -12345;
+         assertFalse(StateSet.stateSetMatches(stateSpec, state));
+     }
+
+     @SmallTest
+     public void testSingleStateNegativeMatches() throws Exception {
+         int[] stateSpec = new int[2];
+         int state;
+         //  match
+         stateSpec[0] = -1;
+         state = 1;
+         assertFalse(StateSet.stateSetMatches(stateSpec, state));
+         // non-match
+         state = 2;
+         assertTrue(StateSet.stateSetMatches(stateSpec, state));
+         // add irrelevant must-not-match
+         stateSpec[1] = -12345;
+         assertTrue(StateSet.stateSetMatches(stateSpec, state));
+     }
+
+     @SmallTest
+     public void testZeroStateOnlyMatchesDefault() throws Exception {
+         int[] stateSpec = new int[3];
+         int state = 0;
+         //  non-match
+         stateSpec[0] = 1;
+         assertFalse(StateSet.stateSetMatches(stateSpec, state));
+         // non-match
+         stateSpec[1] = -1;
+         assertFalse(StateSet.stateSetMatches(stateSpec, state));
+         // match
+         stateSpec = StateSet.WILD_CARD;
+         assertTrue(StateSet.stateSetMatches(stateSpec, state));
+     }
+
+     @SmallTest
+     public void testNullStateOnlyMatchesDefault() throws Exception {
+         int[] stateSpec = new int[3];
+         int[] stateSet = null;
+         //  non-match
+         stateSpec[0] = 1;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         // non-match
+         stateSpec[1] = -1;
+         assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+         // match
+         stateSpec = StateSet.WILD_CARD;
+         assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+     }
+}
diff --git a/tests/CoreTests/android/view/FocusFinderTest.java b/tests/CoreTests/android/view/FocusFinderTest.java
new file mode 100644
index 0000000..7ac8dfc
--- /dev/null
+++ b/tests/CoreTests/android/view/FocusFinderTest.java
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2008 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.view;
+
+import android.graphics.Rect;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class FocusFinderTest extends AndroidTestCase {
+
+    private FocusFinderHelper mFocusFinder;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mFocusFinder = new FocusFinderHelper(FocusFinder.getInstance());
+    }
+
+    @SmallTest
+    public void testPreconditions() {
+        assertNotNull("focus finder instance", mFocusFinder);
+    }
+
+    @SmallTest
+    public void testBelowNotCandidateForDirectionUp() {
+        assertIsNotCandidate(View.FOCUS_UP,
+                new Rect(0, 30, 10, 40),  // src  (left, top, right, bottom)
+                new Rect(0, 50, 10, 60));  // dest (left, top, right, bottom)
+    }
+
+    @SmallTest
+    public void testAboveShareEdgeEdgeOkForDirectionUp() {
+        final Rect src = new Rect(0, 30, 10, 40);
+
+        final Rect dest = new Rect(src);
+        dest.offset(0, -src.height());
+        assertEquals(src.top, dest.bottom);
+
+        assertDirectionIsCandidate(View.FOCUS_UP, src, dest);
+    }
+
+    @SmallTest
+    public void testCompletelyContainedNotCandidate() {
+        assertIsNotCandidate(
+                View.FOCUS_DOWN,
+                //       L  T   R   B
+                new Rect(0, 0,  50, 50),
+                new Rect(0, 1,  50, 49));
+    }
+
+    @SmallTest
+    public void testContinaedWithCommonBottomNotCandidate() {
+        assertIsNotCandidate(
+                View.FOCUS_DOWN,
+                //       L  T   R   B
+                new Rect(0, 0,  50, 50),
+                new Rect(0, 1,  50, 50));
+    }
+
+    @SmallTest
+    public void testOverlappingIsCandidateWhenBothEdgesAreInDirection() {
+        assertDirectionIsCandidate(
+                View.FOCUS_DOWN,
+                //       L  T   R   B
+                new Rect(0, 0,  50, 50),
+                new Rect(0, 1,  50, 51));
+    }
+
+    @SmallTest
+    public void testTopEdgeOfDestAtOrAboveTopOfSrcNotCandidateForDown() {
+        assertIsNotCandidate(
+                View.FOCUS_DOWN,
+                //       L  T   R   B
+                new Rect(0, 0,  50, 50),
+                new Rect(0, 0,  50, 51));
+        assertIsNotCandidate(
+                View.FOCUS_DOWN,
+                //       L  T   R   B
+                new Rect(0, 0,  50, 50),
+                new Rect(0, -1, 50, 51));
+    }
+
+    @SmallTest
+    public void testSameRectBeamsOverlap() {
+        final Rect rect = new Rect(0, 0, 20, 20);
+
+        assertBeamsOverlap(View.FOCUS_LEFT, rect, rect);
+        assertBeamsOverlap(View.FOCUS_RIGHT, rect, rect);
+        assertBeamsOverlap(View.FOCUS_UP, rect, rect);
+        assertBeamsOverlap(View.FOCUS_DOWN, rect, rect);
+    }
+
+    @SmallTest
+    public void testOverlapBeamsRightLeftUpToEdge() {
+        final Rect rect1 = new Rect(0, 0, 20, 20);
+        final Rect rect2 = new Rect(rect1);
+
+        // just below bottom edge
+        rect2.offset(0, rect1.height() - 1);
+        assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
+        assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+        // at edge
+        rect2.offset(0, 1);
+        assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
+        assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+        // just beyond
+        rect2.offset(0, 1);
+        assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2);
+        assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+        // just below top edge
+        rect2.set(rect1);
+        rect2.offset(0, -(rect1.height() - 1));
+        assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
+        assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+        // at top edge
+        rect2.offset(0, -1);
+        assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
+        assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+        // just beyond top edge
+        rect2.offset(0, -1);
+        assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2);
+        assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2);
+    }
+
+    @SmallTest
+    public void testOverlapBeamsUpDownUpToEdge() {
+        final Rect rect1 = new Rect(0, 0, 20, 20);
+        final Rect rect2 = new Rect(rect1);
+
+        // just short of right edge
+        rect2.offset(rect1.width() - 1, 0);
+        assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
+        assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+        // at edge
+        rect2.offset(1, 0);
+        assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
+        assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+        // just beyond
+        rect2.offset(1, 0);
+        assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2);
+        assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+        // just short of left edge
+        rect2.set(rect1);
+        rect2.offset(-(rect1.width() - 1), 0);
+        assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
+        assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+        // at edge
+        rect2.offset(-1, 0);
+        assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
+        assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+        // just beyond edge
+        rect2.offset(-1, 0);
+        assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2);
+        assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2);
+    }
+
+    @SmallTest
+    public void testDirectlyAboveTrumpsAboveLeft() {
+        Rect src = new Rect(0, 50, 20, 70);  // src (left, top, right, bottom)
+
+        Rect directlyAbove = new Rect(src);
+        directlyAbove.offset(0, -(1 + src.height()));
+
+        Rect aboveLeft = new Rect(src);
+        aboveLeft.offset(-(1 + src.width()), -(1 + src.height()));
+
+        assertBetterCandidate(View.FOCUS_UP, src, directlyAbove, aboveLeft);
+    }
+
+    @SmallTest
+    public void testAboveInBeamTrumpsSlightlyCloserOutOfBeam() {
+        Rect src = new Rect(0, 50, 20, 70);  // src (left, top, right, bottom)
+
+        Rect directlyAbove = new Rect(src);
+        directlyAbove.offset(0, -(1 + src.height()));
+
+        Rect aboveLeft = new Rect(src);
+        aboveLeft.offset(-(1 + src.width()), -(1 + src.height()));
+
+        // offset directly above a little further up
+        directlyAbove.offset(0, -5);
+        assertBetterCandidate(View.FOCUS_UP, src, directlyAbove, aboveLeft);
+    }
+
+    @SmallTest
+    public void testOutOfBeamBeatsInBeamUp() {
+
+        Rect src = new Rect(0, 0, 50, 50); // (left, top, right, bottom)
+
+        Rect aboveLeftOfBeam = new Rect(src);
+        aboveLeftOfBeam.offset(-(src.width() + 1), -src.height());
+        assertBeamsDontOverlap(View.FOCUS_UP, src, aboveLeftOfBeam);
+
+        Rect aboveInBeam = new Rect(src);
+        aboveInBeam.offset(0, -src.height());
+        assertBeamsOverlap(View.FOCUS_UP, src, aboveInBeam);
+
+        // in beam wins
+        assertBetterCandidate(View.FOCUS_UP, src, aboveInBeam, aboveLeftOfBeam);
+
+        // still wins while aboveInBeam's bottom edge is < out of beams' top
+        aboveInBeam.offset(0, -(aboveLeftOfBeam.height() - 1));
+        assertTrue("aboveInBeam.bottom > aboveLeftOfBeam.top", aboveInBeam.bottom > aboveLeftOfBeam.top);
+        assertBetterCandidate(View.FOCUS_UP, src, aboveInBeam, aboveLeftOfBeam);
+
+        // cross the threshold: the out of beam prevails
+        aboveInBeam.offset(0, -1);
+        assertEquals(aboveInBeam.bottom, aboveLeftOfBeam.top);
+        assertBetterCandidate(View.FOCUS_UP, src, aboveLeftOfBeam, aboveInBeam);
+    }
+
+    /**
+     * A non-candidate (even a much closer one) is always a worse choice
+     * than a real candidate.
+     */
+    @MediumTest
+    public void testSomeCandidateBetterThanNonCandidate() {
+        Rect src = new Rect(0, 0, 50, 50); // (left, top, right, bottom)
+
+        Rect nonCandidate = new Rect(src);
+        nonCandidate.offset(src.width() + 1, 0);
+
+        assertIsNotCandidate(View.FOCUS_LEFT, src, nonCandidate);
+
+        Rect candidate = new Rect(src);
+        candidate.offset(-(4 * src.width()), 0);
+        assertDirectionIsCandidate(View.FOCUS_LEFT, src, candidate);
+
+        assertBetterCandidate(View.FOCUS_LEFT, src, candidate, nonCandidate);
+    }
+
+    /**
+     * Grabbed from {@link com.android.frameworktest.focus.VerticalFocusSearchTest#testSearchFromMidLeft()}
+     */
+    @SmallTest
+    public void testVerticalFocusSearchScenario() {
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L    T    R    B
+                new Rect(0,   109, 153, 169),   // src
+                new Rect(166, 169, 319, 229),  // expectedbetter
+                new Rect(0,   229, 320, 289)); // expectedworse
+
+        // failing test 4/10/2008, the values were tweaked somehow in functional
+        // test...
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L    T    R    B
+                new Rect(0,   91, 153, 133),   // src
+                new Rect(166, 133, 319, 175),  // expectedbetter
+                new Rect(0,   175, 320, 217)); // expectedworse
+
+    }
+
+    /**
+     * Example: going down from a thin button all the way to the left of a
+     * screen where, just below, is a very wide button, and just below that,
+     * is an equally skinny button all the way to the left.  want to make
+     * sure any minor axis factor doesn't override the fact that the one below
+     * in vertical beam should be next focus
+     */
+    @SmallTest
+    public void testBeamsOverlapMajorAxisCloserMinorAxisFurther() {
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L   T    R    B
+                new Rect(0,  0,   100,  100),  // src
+                new Rect(0,  100, 480,  200),  // expectedbetter
+                new Rect(0,  200, 100,  300)); // expectedworse
+    }
+
+    /**
+     * Real scenario grabbed from song playback screen.
+     */
+    @SmallTest
+    public void testMusicPlaybackScenario() {
+        assertBetterCandidate(View.FOCUS_LEFT,
+                //       L    T    R    B
+                new Rect(227, 185, 312, 231),   // src
+                new Rect(195, 386, 266, 438),   // expectedbetter
+                new Rect(124, 386, 195, 438));  // expectedworse
+    }
+
+    /**
+     * more generalized version of {@link #testMusicPlaybackScenario()}
+     */
+    @SmallTest
+    public void testOutOfBeamOverlapBeatsOutOfBeamFurtherOnMajorAxis() {
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L    T    R    B
+                new Rect(0,   0,   50,  50),   // src
+                new Rect(60,  40,  110, 90),   // expectedbetter
+                new Rect(60,  70,  110, 120));  // expectedworse
+    }
+
+    /**
+     * Make sure that going down prefers views that are actually
+     * down (and not those next to but still a candidate because
+     * they are overlapping on the major axis)
+     */
+    @SmallTest
+    public void testInBeamTrumpsOutOfBeamOverlapping() {
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L    T    R    B
+                new Rect(0,   0,   50,  50),   // src
+                new Rect(0,   60,  50,  110),  // expectedbetter
+                new Rect(51,  1,   101, 51)); // expectedworse
+    }
+
+    @SmallTest
+    public void testOverlappingBeatsNonOverlapping() {
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L    T    R    B
+                new Rect(0,   0,   50,  50),   // src
+                new Rect(0,   40,  50,  90),   // expectedbetter
+                new Rect(0,   75,  50,  125)); // expectedworse
+    }
+
+    @SmallTest
+    public void testEditContactScenarioLeftFromDiscardChangesGoesToSaveContactInLandscape() {
+        assertBetterCandidate(View.FOCUS_LEFT,
+                //       L    T    R    B
+                new Rect(357, 258, 478, 318),  // src
+                new Rect(2,   258, 100, 318),  // better
+                new Rect(106, 120, 424, 184)); // worse
+    }
+
+    /**
+     * A dial pad with 9 squares arranged in a grid.  no padding, so
+     * the edges are equal.  see {@link com.android.frameworktest.focus.LinearLayoutGrid}
+     */
+    @SmallTest
+    public void testGridWithTouchingEdges() {
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L    T    R    B
+                new Rect(106, 49,  212, 192),  // src
+                new Rect(106, 192, 212, 335),  // better
+                new Rect(0,   192, 106, 335)); // worse
+
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L    T    R    B
+                new Rect(106, 49,  212, 192),  // src
+                new Rect(106, 192, 212, 335),  // better
+                new Rect(212, 192, 318, 335)); // worse
+    }
+
+    @SmallTest
+    public void testSearchFromEmptyRect() {
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L   T    R    B
+                new Rect(0,  0,   0,   0),    // src
+                new Rect(0,  0,   320, 45),   // better
+                new Rect(0,  45,  320, 545)); // worse
+    }
+
+    /**
+     * Reproduce bug 1124559, drilling down to actual bug
+     * (majorAxisDistance was wrong for direction left)
+     */
+    @SmallTest
+    public void testGmailReplyButtonsScenario() {
+        assertBetterCandidate(View.FOCUS_LEFT,
+                //       L    T    R    B
+                new Rect(223, 380, 312, 417),  // src
+                new Rect(102, 380, 210, 417),  // better
+                new Rect(111, 443, 206, 480)); // worse
+
+        assertBeamBeats(View.FOCUS_LEFT,
+            //       L    T    R    B
+            new Rect(223, 380, 312, 417),  // src
+            new Rect(102, 380, 210, 417),  // better
+            new Rect(111, 443, 206, 480)); // worse
+
+        assertBeamsOverlap(View.FOCUS_LEFT,
+                //       L    T    R    B
+                new Rect(223, 380, 312, 417),
+                new Rect(102, 380, 210, 417));
+
+        assertBeamsDontOverlap(View.FOCUS_LEFT,
+                //       L    T    R    B
+                new Rect(223, 380, 312, 417),
+                new Rect(111, 443, 206, 480));
+
+        assertTrue(
+                "major axis distance less than major axis distance to "
+                        + "far edge",
+                FocusFinderHelper.majorAxisDistance(View.FOCUS_LEFT,
+                        //       L    T    R    B
+                        new Rect(223, 380, 312, 417),
+                        new Rect(102, 380, 210, 417)) <
+                FocusFinderHelper.majorAxisDistanceToFarEdge(View.FOCUS_LEFT,
+                        //       L    T    R    B
+                        new Rect(223, 380, 312, 417),
+                        new Rect(111, 443, 206, 480)));
+    }
+
+    @SmallTest
+    public void testGmailScenarioBug1203288() {
+        assertBetterCandidate(View.FOCUS_DOWN,
+                //       L    T    R    B
+                new Rect(0,   2,   480, 82),   // src
+                new Rect(344, 87,  475, 124),  // better
+                new Rect(0,   130, 480, 203)); // worse
+    }
+
+    @SmallTest
+    public void testHomeShortcutScenarioBug1295354() {
+        assertBetterCandidate(View.FOCUS_RIGHT,
+                //       L    T    R    B
+                new Rect(3, 338, 77, 413),   // src
+                new Rect(163, 338, 237, 413),  // better
+                new Rect(83, 38, 157, 113)); // worse
+    }
+
+    @SmallTest
+    public void testBeamAlwaysBeatsHoriz() {
+        assertBetterCandidate(View.FOCUS_RIGHT,
+                //       L    T    R    B
+                new Rect(0,   0,   50,  50),   // src
+                new Rect(150, 0,   200, 50),   // better, (way further, but in beam)
+                new Rect(60,  51,  110, 101)); // worse, even though it is closer 
+
+        assertBetterCandidate(View.FOCUS_LEFT,
+                //       L    T    R    B
+                new Rect(150, 0,   200,  50),   // src
+                new Rect(0,   50,  50,   50),   // better, (way further, but in beam)
+                new Rect(49,  99,  149,  101)); // worse, even though it is closer 
+    }
+
+    @SmallTest
+    public void testIsCandidateOverlappingEdgeFromEmptyRect() {
+        assertDirectionIsCandidate(View.FOCUS_DOWN,
+                //       L   T    R    B
+                new Rect(0,  0,   0,   0),   // src
+                new Rect(0,  0,   20,  1));  // candidate
+
+        assertDirectionIsCandidate(View.FOCUS_UP,
+                //       L   T    R    B
+                new Rect(0,  0,   0,   0),   // src
+                new Rect(0,  -1,  20,  0));  // candidate
+
+        assertDirectionIsCandidate(View.FOCUS_LEFT,
+                //       L   T    R    B
+                new Rect(0,  0,   0,   0),    // src
+                new Rect(-1,  0,  0,   20));  // candidate
+
+        assertDirectionIsCandidate(View.FOCUS_RIGHT,
+                //       L   T    R    B
+                new Rect(0,  0,   0,   0),    // src
+                new Rect(0,  0,   1,   20));  // candidate
+    }
+
+    private void assertBeamsOverlap(int direction, Rect rect1, Rect rect2) {
+        String directionStr = validateAndGetStringFor(direction);
+        String assertMsg = String.format("Expected beams to overlap in direction %s "
+                + "for rectangles %s and %s", directionStr, rect1, rect2);
+        assertTrue(assertMsg, mFocusFinder.beamsOverlap(direction, rect1, rect2));
+    }
+
+    private void assertBeamsDontOverlap(int direction, Rect rect1, Rect rect2) {
+        String directionStr = validateAndGetStringFor(direction);
+        String assertMsg = String.format("Expected beams not to overlap in direction %s "
+                + "for rectangles %s and %s", directionStr, rect1, rect2);
+        assertFalse(assertMsg, mFocusFinder.beamsOverlap(direction, rect1, rect2));
+    }
+
+    /**
+     * Assert that particular rect is a better focus search candidate from a
+     * source rect than another.
+     * @param direction The direction of focus search.
+     * @param srcRect The src rectangle.
+     * @param expectedBetter The candidate that should be better.
+     * @param expectedWorse The candidate that should be worse.
+     */
+    private void assertBetterCandidate(int direction, Rect srcRect,
+            Rect expectedBetter, Rect expectedWorse) {
+
+        String directionStr = validateAndGetStringFor(direction);
+        String assertMsg = String.format(
+                "expected %s to be a better focus search candidate than "
+                        + "%s when searching "
+                        + "from %s in direction %s",
+                expectedBetter, expectedWorse, srcRect, directionStr);
+
+        assertTrue(assertMsg,
+                mFocusFinder.isBetterCandidate(direction, srcRect,
+                        expectedBetter, expectedWorse));
+
+        assertMsg = String.format(
+                "expected %s to not be a better focus search candidate than "
+                        + "%s when searching "
+                        + "from %s in direction %s",
+                expectedWorse, expectedBetter, srcRect, directionStr);
+
+        assertFalse(assertMsg,
+                mFocusFinder.isBetterCandidate(direction, srcRect,
+                        expectedWorse, expectedBetter));
+    }
+
+    private void assertIsNotCandidate(int direction, Rect src, Rect dest) {
+        String directionStr = validateAndGetStringFor(direction);
+
+        final String assertMsg = String.format(
+                "expected going from %s to %s in direction %s to be an invalid "
+                        + "focus search candidate",
+                src, dest, directionStr);
+        assertFalse(assertMsg, mFocusFinder.isCandidate(src, dest, direction));
+    }
+
+    private void assertBeamBeats(int direction, Rect srcRect,
+            Rect rect1, Rect rect2) {
+
+        String directionStr = validateAndGetStringFor(direction);
+        String assertMsg = String.format(
+                "expecting %s to beam beat %s w.r.t %s in direction %s",
+                rect1, rect2, srcRect, directionStr);
+        assertTrue(assertMsg, mFocusFinder.beamBeats(direction, srcRect, rect1, rect2));
+    }
+
+
+    private void assertDirectionIsCandidate(int direction, Rect src, Rect dest) {
+        String directionStr = validateAndGetStringFor(direction);
+
+        final String assertMsg = String.format(
+                "expected going from %s to %s in direction %s to be a valid "
+                        + "focus search candidate",
+                src, dest, directionStr);
+        assertTrue(assertMsg, mFocusFinder.isCandidate(src, dest, direction));
+    }
+
+    private String validateAndGetStringFor(int direction) {
+        String directionStr = "??";
+        switch(direction) {
+            case View.FOCUS_UP:
+                directionStr = "FOCUS_UP";
+                break;
+            case View.FOCUS_DOWN:
+                directionStr = "FOCUS_DOWN";
+                break;
+            case View.FOCUS_LEFT:
+                directionStr = "FOCUS_LEFT";
+                break;
+            case View.FOCUS_RIGHT:
+                directionStr = "FOCUS_RIGHT";
+                break;
+            default:
+                fail("passed in unknown direction, ya blewit!");
+        }
+        return directionStr;
+    }
+
+
+}
diff --git a/tests/CoreTests/android/view/MockView.java b/tests/CoreTests/android/view/MockView.java
new file mode 100644
index 0000000..1d416bd
--- /dev/null
+++ b/tests/CoreTests/android/view/MockView.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 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.view;
+
+/**
+ * Mock View class for testing
+ */
+
+public class MockView extends View{
+
+}
diff --git a/tests/CoreTests/android/view/ViewGroupAttributesTest.java b/tests/CoreTests/android/view/ViewGroupAttributesTest.java
new file mode 100644
index 0000000..b4ef0e7
--- /dev/null
+++ b/tests/CoreTests/android/view/ViewGroupAttributesTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 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.view;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ViewGroupAttributesTest extends AndroidTestCase {
+
+    private MyViewGroup mViewGroup;
+
+    private static final class MyViewGroup extends ViewGroup {
+
+        public MyViewGroup(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        }
+        
+        @Override
+        public boolean isChildrenDrawnWithCacheEnabled() {
+            return super.isChildrenDrawnWithCacheEnabled();
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mViewGroup = new MyViewGroup(getContext());
+    }
+
+    @SmallTest
+    public void testDescendantFocusabilityEnum() {
+        assertEquals("expected ViewGroup.FOCUS_BEFORE_DESCENDANTS to be default",
+                ViewGroup.FOCUS_BEFORE_DESCENDANTS, mViewGroup.getDescendantFocusability());
+
+        // remember some state before we muck with flags
+        final boolean isAnimationCachEnabled = mViewGroup.isAnimationCacheEnabled();
+        final boolean isAlwaysDrawnWithCacheEnabled = mViewGroup.isAlwaysDrawnWithCacheEnabled();
+        final boolean isChildrenDrawnWithCacheEnabled = mViewGroup.isChildrenDrawnWithCacheEnabled();
+
+        mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+        assertEquals(ViewGroup.FOCUS_AFTER_DESCENDANTS, mViewGroup.getDescendantFocusability());
+
+        mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        assertEquals(ViewGroup.FOCUS_BLOCK_DESCENDANTS, mViewGroup.getDescendantFocusability());
+
+        mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+        assertEquals(ViewGroup.FOCUS_BEFORE_DESCENDANTS, mViewGroup.getDescendantFocusability());
+
+        // verify we didn't change something unrelated
+        final String msg = "setDescendantFocusability messed with an unrelated flag";
+        assertEquals(msg, isAnimationCachEnabled, mViewGroup.isAnimationCacheEnabled());
+        assertEquals(msg, isAlwaysDrawnWithCacheEnabled, mViewGroup.isAlwaysDrawnWithCacheEnabled());
+        assertEquals(msg, isChildrenDrawnWithCacheEnabled, mViewGroup.isChildrenDrawnWithCacheEnabled());
+    }
+
+    @SmallTest
+    public void testWrongIntSetForDescendantFocusabilityEnum() {
+        try {
+            mViewGroup.setDescendantFocusability(0);
+            fail("expected setting wrong flag to throw an exception");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+}
diff --git a/tests/CoreTests/android/webkit/CookieTest.java b/tests/CoreTests/android/webkit/CookieTest.java
new file mode 100644
index 0000000..1c3d671
--- /dev/null
+++ b/tests/CoreTests/android/webkit/CookieTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2008 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.webkit;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+
+public class CookieTest extends AndroidTestCase {
+
+    /**
+     * To run these tests: $ mmm frameworks/base/tests/CoreTests/android && adb
+     * remount && adb sync $ adb shell am instrument -w \ -e class
+     * android.webkit.CookieTest \
+     * android.core/android.test.InstrumentationTestRunner
+     */
+
+    private CookieManager mCookieManager;
+
+    @Override
+    public void setContext(Context context) {
+        assertTrue(mContext == null);
+        super.setContext(context);
+        CookieSyncManager.createInstance(context);
+        mCookieManager = CookieManager.getInstance();
+        mCookieManager.removeAllCookie();
+    }
+
+    public void testParse() {
+        mCookieManager.removeAllCookie();
+        String url = "http://www.foo.com";
+
+        // basic
+        mCookieManager.setCookie(url, "a=b");
+        String cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie.equals("a=b"));
+
+        // quoted
+        mCookieManager.setCookie(url, "c=\"d;\"");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie.equals("a=b; c=\"d;\""));
+    }
+
+    public void testDomain() {
+        mCookieManager.removeAllCookie();
+        String url = "http://www.foo.com";
+
+        // basic
+        mCookieManager.setCookie(url, "a=b");
+        String cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie.equals("a=b"));
+
+        // no cross domain cookie
+        cookie = mCookieManager.getCookie("http://bar.com");
+        assertTrue(cookie == null);
+
+        // more than one cookie
+        mCookieManager.setCookie(url, "c=d; domain=.foo.com");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie.equals("a=b; c=d"));
+
+        // host cookie should not be accessible from a sub-domain.
+        cookie = mCookieManager.getCookie("http://bar.www.foo.com");
+        assertTrue(cookie.equals("c=d"));
+
+        // test setting a domain= that doesn't start w/ a dot, should
+        // treat it as a domain cookie, as if there was a pre-pended dot.
+        mCookieManager.setCookie(url, "e=f; domain=www.foo.com");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie.equals("a=b; c=d; e=f"));
+        cookie = mCookieManager.getCookie("http://sub.www.foo.com");
+        assertTrue(cookie.equals("c=d; e=f"));
+        cookie = mCookieManager.getCookie("http://foo.com");
+        assertTrue(cookie.equals("c=d"));
+    }
+
+    public void testSubDomain() {
+        mCookieManager.removeAllCookie();
+        String url_abcd = "http://a.b.c.d.com";
+        String url_bcd = "http://b.c.d.com";
+        String url_cd = "http://c.d.com";
+        String url_d = "http://d.com";
+
+        mCookieManager.setCookie(url_abcd, "a=1; domain=.a.b.c.d.com");
+        mCookieManager.setCookie(url_abcd, "b=2; domain=.b.c.d.com");
+        mCookieManager.setCookie(url_abcd, "c=3; domain=.c.d.com");
+        mCookieManager.setCookie(url_abcd, "d=4; domain=.d.com");
+
+        String cookie = mCookieManager.getCookie(url_abcd);
+        assertTrue(cookie.equals("a=1; b=2; c=3; d=4"));
+        cookie = mCookieManager.getCookie(url_bcd);
+        assertTrue(cookie.equals("b=2; c=3; d=4"));
+        cookie = mCookieManager.getCookie(url_cd);
+        assertTrue(cookie.equals("c=3; d=4"));
+        cookie = mCookieManager.getCookie(url_d);
+        assertTrue(cookie.equals("d=4"));
+
+        // check that the same cookie can exist on different sub-domains.
+        mCookieManager.setCookie(url_bcd, "x=bcd; domain=.b.c.d.com");
+        mCookieManager.setCookie(url_bcd, "x=cd; domain=.c.d.com");
+        cookie = mCookieManager.getCookie(url_bcd);
+        assertTrue(cookie.equals("b=2; c=3; d=4; x=bcd; x=cd"));
+        cookie = mCookieManager.getCookie(url_cd);
+        assertTrue(cookie.equals("c=3; d=4; x=cd"));
+    }
+
+    public void testInvalidDomain() {
+        mCookieManager.removeAllCookie();
+        String url = "http://foo.bar.com";
+
+        mCookieManager.setCookie(url, "a=1; domain=.yo.foo.bar.com");
+        String cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+
+        mCookieManager.setCookie(url, "b=2; domain=.foo.com");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+
+        mCookieManager.setCookie(url, "c=3; domain=.bar.foo.com");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+
+        mCookieManager.setCookie(url, "d=4; domain=.foo.bar.com.net");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+
+        mCookieManager.setCookie(url, "e=5; domain=.ar.com");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+
+        mCookieManager.setCookie(url, "f=6; domain=.com");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+
+        mCookieManager.setCookie(url, "g=7; domain=.co.uk");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+
+        mCookieManager.setCookie(url, "h=8; domain=.foo.bar.com.com");
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+    }
+
+    public void testPath() {
+        mCookieManager.removeAllCookie();
+        String url = "http://www.foo.com";
+
+        mCookieManager.setCookie(url, "a=b; path=/wee");
+        String cookie = mCookieManager.getCookie(url + "/wee");
+        assertTrue(cookie.equals("a=b"));
+        cookie = mCookieManager.getCookie(url + "/wee/");
+        assertTrue(cookie.equals("a=b"));
+        cookie = mCookieManager.getCookie(url + "/wee/hee");
+        assertTrue(cookie.equals("a=b"));
+        cookie = mCookieManager.getCookie(url + "/wee/hee/more");
+        assertTrue(cookie.equals("a=b"));
+        cookie = mCookieManager.getCookie(url + "/weehee");
+        assertTrue(cookie == null);
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie == null);
+
+        mCookieManager.setCookie(url, "a=c; path=");
+        cookie = mCookieManager.getCookie(url + "/wee");
+        assertTrue(cookie.equals("a=b; a=c"));
+        cookie = mCookieManager.getCookie(url);
+        assertTrue(cookie.equals("a=c"));
+
+        mCookieManager.setCookie(url, "a=d");
+        cookie = mCookieManager.getCookie(url + "/wee");
+        assertTrue(cookie.equals("a=b; a=c; a=d"));
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java b/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java
new file mode 100644
index 0000000..81727e4
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ATResponseParserTest extends TestCase {
+    @SmallTest
+    public void testBasic() throws Exception {
+        ATResponseParser p = new ATResponseParser("+CREG: 0");
+
+        assertEquals(0, p.nextInt());
+
+        assertFalse(p.hasMore());
+
+        try {
+            p.nextInt();
+            fail("exception expected");
+        } catch (ATParseEx ex) {
+            //test pass
+        }
+
+        p = new ATResponseParser("+CREG: 0,1");
+        assertEquals(0, p.nextInt());
+        assertEquals(1, p.nextInt());
+        assertFalse(p.hasMore());
+
+        p = new ATResponseParser("+CREG: 0, 1");
+        assertEquals(0, p.nextInt());
+        assertEquals(1, p.nextInt());
+        assertFalse(p.hasMore());
+
+        p = new ATResponseParser("+CREG: 0, 1,");
+        assertEquals(0, p.nextInt());
+        assertEquals(1, p.nextInt());
+        // this seems odd but is probably OK
+        assertFalse(p.hasMore());
+        try {
+            p.nextInt();
+            fail("exception expected");
+        } catch (ATParseEx ex) {
+            //test pass
+        }
+
+        p = new ATResponseParser("+CREG: 0, 1 ");
+        assertEquals(0, p.nextInt());
+        assertEquals(1, p.nextInt());
+        assertFalse(p.hasMore());
+
+        p = new ATResponseParser("0, 1 ");
+        // no prefix -> exception
+        try {
+            p.nextInt();
+            fail("exception expected");
+        } catch (ATParseEx ex) {
+            //test pass
+        }
+
+        p = new ATResponseParser("+CREG: 0, 1, 5");
+        assertFalse(p.nextBoolean());
+        assertTrue(p.nextBoolean());
+        try {
+            // is this over-constraining?
+            p.nextBoolean();
+            fail("exception expected");
+        } catch (ATParseEx ex) {
+            //test pass
+        }
+
+        p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212\",145");
+
+        assertEquals(1, p.nextInt());
+        assertFalse(p.nextBoolean());
+        assertEquals(2, p.nextInt());
+        assertEquals(0, p.nextInt());
+        assertEquals(0, p.nextInt());
+        assertEquals("+18005551212", p.nextString());
+        assertEquals(145, p.nextInt());
+        assertFalse(p.hasMore());
+
+        p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212,145");
+
+        assertEquals(1, p.nextInt());
+        assertFalse(p.nextBoolean());
+        assertEquals(2, p.nextInt());
+        assertEquals(0, p.nextInt());
+        assertEquals(0, p.nextInt());
+        try {
+            p.nextString();
+            fail("expected ex");
+        } catch (ATParseEx ex) {
+            //test pass
+        }
+
+        p = new ATResponseParser("+FOO: \"\"");
+        assertEquals("", p.nextString());
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
new file mode 100644
index 0000000..e8bd239
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.SpannableStringBuilder;
+import android.telephony.PhoneNumberUtils;
+
+import junit.framework.TestCase;
+
+public class PhoneNumberUtilsTest extends TestCase {
+
+    @SmallTest
+    public void testA() throws Exception {
+        assertEquals(
+                "+17005554141",
+                PhoneNumberUtils.extractNetworkPortion("+17005554141")
+        );
+
+        assertEquals(
+                "+17005554141",
+                PhoneNumberUtils.extractNetworkPortion("+1 (700).555-4141")
+        );
+
+        assertEquals(
+                "17005554141",
+                PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141")
+        );
+
+        // This may seem wrong, but it's probably ok
+        assertEquals(
+                "17005554141*#",
+                PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141*#")
+        );
+
+        assertEquals(
+                "170055541NN",
+                PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN")
+        );
+
+        assertEquals(
+                "170055541NN",
+                PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN,1234")
+        );
+
+        assertEquals(
+                "170055541NN",
+                PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN;1234")
+        );
+
+        // An MMI string is unperterbed, even though it contains a
+        // (valid in this case) embedded +
+        assertEquals(
+                "**21**17005554141#",
+                PhoneNumberUtils.extractNetworkPortion("**21**+17005554141#")
+                //TODO this is the correct result, although the above
+                //result has been returned since change 31776
+                //"**21**+17005554141#"
+        );
+
+        assertEquals("", PhoneNumberUtils.extractNetworkPortion(""));
+
+        assertEquals("", PhoneNumberUtils.extractNetworkPortion(",1234"));
+
+        byte [] b = new byte[20];
+        b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55;
+        b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0;
+        assertEquals("17005550020",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 7));
+
+        b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55;
+        b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0;
+        assertEquals("+17005550020",
+                PhoneNumberUtils.calledPartyBCDToString(b, 0, 7));
+
+        byte[] bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("+17005550020");
+        assertEquals(7, bRet.length);
+        for (int i = 0; i < 7; i++) {
+            assertEquals(b[i], bRet[i]);
+        }
+
+        bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("7005550020");
+        assertEquals("7005550020",
+            PhoneNumberUtils.calledPartyBCDToString(bRet, 0, bRet.length));
+
+        b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55;
+        b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0;
+        assertEquals("17005550020#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 7));
+
+        b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55;
+        b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0;
+        assertEquals("+17005550020#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 7));
+
+        b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1;
+        assertEquals("*21#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 3));
+
+        b[0] = (byte) 0x81; b[1] = (byte) 0x2B; b[2] = (byte) 0xB1;
+        assertEquals("#21#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 3));
+
+        b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1;
+        assertEquals("*21#+",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 3));
+
+        b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB;
+        assertEquals("**21#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 4));
+
+        b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB;
+        assertEquals("**21#+",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 4));
+
+        b[0] = (byte) 0x81; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71;
+        b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20;
+        b[8] = (byte) 0xB0;
+        assertEquals("*99*17005550020#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 9));
+
+        b[0] = (byte) 0x91; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71;
+        b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20;
+        b[8] = (byte) 0xB0;
+        assertEquals("*99*+17005550020#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 9));
+
+        b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A;
+        b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00;
+        b[8] = (byte) 0x02; b[9] = (byte) 0xFB;
+        assertEquals("**21*17005550020#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 10));
+
+        b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A;
+        b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00;
+        b[8] = (byte) 0x02; b[9] = (byte) 0xFB;
+        assertEquals("**21*+17005550020#",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 10));
+
+        b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xA1; b[3] = (byte) 0x71;
+        b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20;
+        b[8] = (byte) 0xF0;
+        assertEquals("*21*17005550020",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 9));
+
+        b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; b[3] = (byte) 0x71;
+        b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20;
+        b[8] = (byte) 0xF0;
+        assertEquals("*21#+17005550020",
+            PhoneNumberUtils.calledPartyBCDToString(b, 0, 9));
+
+        assertNull(PhoneNumberUtils.extractNetworkPortion(null));
+        assertNull(PhoneNumberUtils.extractPostDialPortion(null));
+        assertTrue(PhoneNumberUtils.compare(null, null));
+        assertFalse(PhoneNumberUtils.compare(null, "123"));
+        assertFalse(PhoneNumberUtils.compare("123", null));
+        assertNull(PhoneNumberUtils.toCallerIDMinMatch(null));
+        assertNull(PhoneNumberUtils.getStrippedReversed(null));
+        assertNull(PhoneNumberUtils.stringFromStringAndTOA(null, 1));
+    }
+
+    @SmallTest
+    public void testB() throws Exception {
+        assertEquals("", PhoneNumberUtils.extractPostDialPortion("+17005554141"));
+        assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-4141"));
+        assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN"));
+        assertEquals(",1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN,1234"));
+        assertEquals(";1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1234"));
+        assertEquals(";1234,;N",
+                PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1-2.34 ,;N"));
+    }
+
+    @SmallTest
+    public void testCompare() throws Exception {
+        // this is odd
+        assertFalse(PhoneNumberUtils.compare("", ""));
+
+        assertTrue(PhoneNumberUtils.compare("911", "911"));
+        assertFalse(PhoneNumberUtils.compare("911", "18005550911"));
+        assertTrue(PhoneNumberUtils.compare("5555", "5555"));
+        assertFalse(PhoneNumberUtils.compare("5555", "180055555555"));
+
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "+17005554141"));
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141"));
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141,1234"));
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "17005554141"));
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "7005554141"));
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "5554141"));
+        assertTrue(PhoneNumberUtils.compare("17005554141", "5554141"));
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "01117005554141"));
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "0017005554141"));
+        assertTrue(PhoneNumberUtils.compare("17005554141", "0017005554141"));
+
+
+        assertTrue(PhoneNumberUtils.compare("+17005554141", "**31#+17005554141"));
+
+        assertFalse(PhoneNumberUtils.compare("+1 999 7005554141", "+1 7005554141"));
+        assertTrue(PhoneNumberUtils.compare("011 1 7005554141", "7005554141"));
+
+        assertFalse(PhoneNumberUtils.compare("011 11 7005554141", "+17005554141"));
+
+        assertFalse(PhoneNumberUtils.compare("+17005554141", "7085882300"));
+
+        assertTrue(PhoneNumberUtils.compare("+44 207 792 3490", "0 207 792 3490"));
+
+        assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "00 207 792 3490"));
+        assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "011 207 792 3490"));
+
+        /***** FIXME's ******/
+        //
+        // MMI header should be ignored
+        assertFalse(PhoneNumberUtils.compare("+17005554141", "**31#17005554141"));
+
+        // It's too bad this is false
+        // +44 (0) 207 792 3490 is not a dialable number
+        // but it is commonly how European phone numbers are written
+        assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "+44 (0) 207 792 3490"));
+
+        // The japanese international prefix, for example, messes us up
+        // But who uses a GSM phone in Japan?
+        assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "010 44 207 792 3490"));
+
+        // The Australian one messes us up too
+        assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "0011 44 207 792 3490"));
+
+        // The Russian trunk prefix messes us up, as does current
+        // Russian area codes (which bein with 0)
+
+        assertFalse(PhoneNumberUtils.compare("+7(095)9100766", "8(095)9100766"));
+
+        // 444 is not a valid country code, but
+        // matchIntlPrefixAndCC doesnt know this
+        assertTrue(PhoneNumberUtils.compare("+444 207 792 3490", "0 207 792 3490"));
+    }
+
+
+    @SmallTest
+    public void testToCallerIDIndexable() throws Exception {
+        assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("17005554141"));
+        assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141"));
+        assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141,1234"));
+        assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141;1234"));
+
+        //this seems wrong, or at least useless
+        assertEquals("NN145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-41NN"));
+
+        //<shrug> -- these are all not useful, but not terribly wrong
+        assertEquals("", PhoneNumberUtils.toCallerIDMinMatch(""));
+        assertEquals("0032", PhoneNumberUtils.toCallerIDMinMatch("2300"));
+        assertEquals("0032+", PhoneNumberUtils.toCallerIDMinMatch("+2300"));
+        assertEquals("#130#", PhoneNumberUtils.toCallerIDMinMatch("*#031#"));
+    }
+
+    @SmallTest
+    public void testGetIndexable() throws Exception {
+        assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141"));
+        assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141,1234"));
+        assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141;1234"));
+
+        //this seems wrong, or at least useless
+        assertEquals("NN145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-41NN"));
+
+        //<shrug> -- these are all not useful, but not terribly wrong
+        assertEquals("", PhoneNumberUtils.getStrippedReversed(""));
+        assertEquals("0032", PhoneNumberUtils.getStrippedReversed("2300"));
+        assertEquals("0032+", PhoneNumberUtils.getStrippedReversed("+2300"));
+        assertEquals("#130#*", PhoneNumberUtils.getStrippedReversed("*#031#"));
+    }
+
+    @SmallTest
+    public void testNanpFormatting() {
+        SpannableStringBuilder number = new SpannableStringBuilder();
+        number.append("8005551212");
+        PhoneNumberUtils.formatNanpNumber(number);
+        assertEquals("800-555-1212", number.toString());
+
+        number.clear();
+        number.append("800555121");
+        PhoneNumberUtils.formatNanpNumber(number);
+        assertEquals("800-555-121", number.toString());
+
+        number.clear();
+        number.append("555-1212");
+        PhoneNumberUtils.formatNanpNumber(number);
+        assertEquals("555-1212", number.toString());
+
+        number.clear();
+        number.append("800-55512");
+        PhoneNumberUtils.formatNanpNumber(number);
+        assertEquals("800-555-12", number.toString());
+    }
+
+    @SmallTest
+    public void testConvertKeypadLettersToDigits() {
+        assertEquals("1-800-4664-411",
+                     PhoneNumberUtils.convertKeypadLettersToDigits("1-800-GOOG-411"));
+        assertEquals("18004664411",
+                     PhoneNumberUtils.convertKeypadLettersToDigits("1800GOOG411"));
+        assertEquals("1-800-466-4411",
+                     PhoneNumberUtils.convertKeypadLettersToDigits("1-800-466-4411"));
+        assertEquals("18004664411",
+                     PhoneNumberUtils.convertKeypadLettersToDigits("18004664411"));
+        assertEquals("222-333-444-555-666-7777-888-9999",
+                     PhoneNumberUtils.convertKeypadLettersToDigits(
+                             "ABC-DEF-GHI-JKL-MNO-PQRS-TUV-WXYZ"));
+        assertEquals("222-333-444-555-666-7777-888-9999",
+                     PhoneNumberUtils.convertKeypadLettersToDigits(
+                             "abc-def-ghi-jkl-mno-pqrs-tuv-wxyz"));
+        assertEquals("(800) 222-3334",
+                     PhoneNumberUtils.convertKeypadLettersToDigits("(800) ABC-DEFG"));
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java
new file mode 100644
index 0000000..88eaecd
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 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.internal.telephony;
+
+import android.telephony.PhoneNumberFormattingTextWatcher;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.TextWatcher;
+
+import junit.framework.TestCase;
+
+public class PhoneNumberWatcherTest extends TestCase {
+    @SmallTest
+    public void testHyphenation() throws Exception {
+        SpannableStringBuilder number = new SpannableStringBuilder();
+        TextWatcher tw = new PhoneNumberFormattingTextWatcher();
+        number.append("555-1212");
+        // Move the cursor to the left edge
+        Selection.setSelection(number, 0);
+        tw.beforeTextChanged(number, 0, 0, 1);
+        // Insert an 8 at the beginning
+        number.insert(0, "8");
+        tw.afterTextChanged(number);
+        assertEquals("855-512-12", number.toString());
+    }
+    
+    @SmallTest
+    public void testHyphenDeletion() throws Exception {
+        SpannableStringBuilder number = new SpannableStringBuilder();
+        TextWatcher tw = new PhoneNumberFormattingTextWatcher();
+        number.append("555-1212");
+        // Move the cursor to after the hyphen
+        Selection.setSelection(number, 4);
+        // Delete the hyphen
+        tw.beforeTextChanged(number, 3, 1, 0);
+        number.delete(3, 4);
+        tw.afterTextChanged(number);
+        // Make sure that it deleted the character before the hyphen 
+        assertEquals("551-212", number.toString());
+        
+        // Make sure it deals with left edge boundary case
+        number.insert(0, "-");
+        Selection.setSelection(number, 1);
+        tw.beforeTextChanged(number, 0, 1, 0);
+        number.delete(0, 1);
+        tw.afterTextChanged(number);
+        // Make sure that it deleted the character before the hyphen 
+        assertEquals("551-212", number.toString());
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
new file mode 100644
index 0000000..eb2bd23
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.gsm.AdnRecordTest;
+import com.android.internal.telephony.gsm.GSMPhoneTest;
+import com.android.internal.telephony.gsm.GsmAlphabetTest;
+import com.android.internal.telephony.gsm.SMSDispatcherTest;
+import com.android.internal.telephony.gsm.SimPhoneBookTest;
+import com.android.internal.telephony.gsm.SimSmsTest;
+import com.android.internal.telephony.gsm.SimUtilsTest;
+
+import junit.framework.TestSuite;
+
+/**
+ * To run these tests:
+ * $ mmm java/tests && adb sync
+ * $ adb shell am instrument -w \
+ *    -e class com.android.internal.telephony.TelephonyTests \
+ *    android.core/android.test.InstrumentationTestRunner
+ */
+public class TelephonyTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(TelephonyTests.class.getName());
+
+        suite.addTestSuite(PhoneNumberWatcherTest.class);
+        suite.addTestSuite(ATResponseParserTest.class);
+        suite.addTestSuite(PhoneNumberUtilsTest.class);
+        suite.addTestSuite(SMSDispatcherTest.class);
+        //suite.addTestSuite(GSMPhoneTest.class);
+        suite.addTestSuite(AdnRecordTest.class);
+        suite.addTestSuite(GsmAlphabetTest.class);
+        suite.addTestSuite(SimUtilsTest.class);
+        suite.addTestSuite(SimPhoneBookTest.class);
+        suite.addTestSuite(SimSmsTest.class);
+
+        return suite;
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java b/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java
new file mode 100644
index 0000000..427795b
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+/**
+ * Stub class used for unit tests
+ */
+
+public class TestPhoneNotifier implements PhoneNotifier {
+    public TestPhoneNotifier() {
+    }
+
+    public void notifyPhoneState(Phone sender) {
+    }
+
+    public void notifyServiceState(Phone sender) {
+    }
+
+    public void notifyCellLocation(Phone sender) {
+    }
+    
+    public void notifySignalStrength(Phone sender) {
+    }
+
+    public void notifyMessageWaitingChanged(Phone sender) {
+    }
+
+    public void notifyCallForwardingChanged(Phone sender) {
+    }
+
+    public void notifyDataConnection(Phone sender, String reason) {
+    }
+
+    public void notifyDataConnectionFailed(Phone sender, String reason) {
+    }
+
+    public void notifyDataActivity(Phone sender) {
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java
new file mode 100644
index 0000000..6cafdf0
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * {@hide}
+ */
+public class AdnRecordTest extends TestCase {
+    
+    @SmallTest
+    public void testBasic() throws Exception {
+        AdnRecord adn;
+
+        //
+        // Typical record
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes("566F696365204D61696C07918150367742F3FFFFFFFFFFFF"));
+
+        assertEquals("Voice Mail", adn.getAlphaTag());
+        assertEquals("+18056377243", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // Empty records, empty strings
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+
+        assertEquals("", adn.getAlphaTag());
+        assertEquals("", adn.getNumber());
+        assertTrue(adn.isEmpty());
+
+        //
+        // Record too short
+        // 
+        adn = new AdnRecord(SimUtils.hexStringToBytes( "FF"));
+
+        assertEquals("", adn.getAlphaTag());
+        assertEquals("", adn.getNumber());
+        assertTrue(adn.isEmpty());
+
+        //
+        // TOA = 0xff ("control string")
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes("566F696365204D61696C07FF8150367742F3FFFFFFFFFFFF"));
+
+        assertEquals("Voice Mail", adn.getAlphaTag());
+        assertEquals("18056377243", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // TOA = 0x81 (unknown)
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes("566F696365204D61696C07818150367742F3FFFFFFFFFFFF"));
+
+        assertEquals("Voice Mail", adn.getAlphaTag());
+        assertEquals("18056377243", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // Number Length is too long
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes("566F696365204D61696C0F918150367742F3FFFFFFFFFFFF"));
+
+        assertEquals("Voice Mail", adn.getAlphaTag());
+        assertEquals("", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // Number Length is zero (invalid)
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes("566F696365204D61696C00918150367742F3FFFFFFFFFFFF"));
+
+        assertEquals("Voice Mail", adn.getAlphaTag());
+        assertEquals("", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // Number Length is 2, first number byte is FF, TOA is international
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes("566F696365204D61696C0291FF50367742F3FFFFFFFFFFFF"));
+
+        assertEquals("Voice Mail", adn.getAlphaTag());
+        assertEquals("", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // Number Length is 2, first number digit is valid, TOA is international
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes("566F696365204D61696C0291F150367742F3FFFFFFFFFFFF"));
+
+        assertEquals("Voice Mail", adn.getAlphaTag());
+        assertEquals("+1", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // An extended record
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes(
+                        "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01"));
+
+        assertEquals("Adgjm", adn.getAlphaTag());
+        assertEquals("+18885551212,12345678", adn.getNumber());
+        assertFalse(adn.isEmpty());
+        assertTrue(adn.hasExtendedRecord());
+
+        adn.appendExtRecord(SimUtils.hexStringToBytes("0206092143658709ffffffffff"));
+
+        assertEquals("Adgjm", adn.getAlphaTag());
+        assertEquals("+18885551212,12345678901234567890", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // An extended record with an invalid extension
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes(
+                        "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01"));
+
+        assertEquals("Adgjm", adn.getAlphaTag());
+        assertEquals("+18885551212,12345678", adn.getNumber());
+        assertFalse(adn.isEmpty());
+        assertTrue(adn.hasExtendedRecord());
+
+        adn.appendExtRecord(SimUtils.hexStringToBytes("0106092143658709ffffffffff"));
+
+        assertEquals("Adgjm", adn.getAlphaTag());
+        assertEquals("+18885551212,12345678", adn.getNumber());
+        assertFalse(adn.isEmpty());
+
+        //
+        // An extended record with an invalid extension
+        // 
+        adn = new AdnRecord(
+                SimUtils.hexStringToBytes(
+                        "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01"));
+
+        assertEquals("Adgjm", adn.getAlphaTag());
+        assertEquals("+18885551212,12345678", adn.getNumber());
+        assertFalse(adn.isEmpty());
+        assertTrue(adn.hasExtendedRecord());
+
+        adn.appendExtRecord(SimUtils.hexStringToBytes("020B092143658709ffffffffff"));
+
+        assertEquals("Adgjm", adn.getAlphaTag());
+        assertEquals("+18885551212,12345678", adn.getNumber());
+        assertFalse(adn.isEmpty());
+    }
+}
+
+
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
new file mode 100644
index 0000000..7107412
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
@@ -0,0 +1,1938 @@
+/*
+ * Copyright (C) 2007 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 GSMTestHandler.ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.telephony.ServiceState;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+import android.util.Log;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.MmiCode;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TestPhoneNotifier;
+import com.android.internal.telephony.gsm.CallFailCause;
+import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.gsm.GSMTestHandler;
+import com.android.internal.telephony.gsm.GsmMmiCode;
+import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.test.SimulatedCommands;
+import com.android.internal.telephony.test.SimulatedRadioControl;
+
+import java.util.List;
+
+
+public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase {
+    private SimulatedRadioControl mRadioControl;
+    private GSMPhone mGSMPhone;
+    private GSMTestHandler mGSMTestHandler;
+    private Handler mHandler;
+
+    private static final int EVENT_PHONE_STATE_CHANGED = 1;
+    private static final int EVENT_DISCONNECT = 2;
+    private static final int EVENT_RINGING = 3;
+    private static final int EVENT_CHANNEL_OPENED = 4;
+    private static final int EVENT_POST_DIAL = 5;
+    private static final int EVENT_DONE = 6;
+    private static final int EVENT_SSN = 7;
+    private static final int EVENT_MMI_INITIATE = 8;
+    private static final int EVENT_MMI_COMPLETE = 9;
+    private static final int EVENT_IN_SERVICE = 10;
+    private static final int SUPP_SERVICE_FAILED = 11;
+    private static final int SERVICE_STATE_CHANGED = 12;
+    private static final int EVENT_OEM_RIL_MESSAGE = 13;
+    public static final int ANY_MESSAGE = -1;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mGSMTestHandler = new GSMTestHandler(mContext);
+
+        mGSMTestHandler.start();
+        synchronized (mGSMTestHandler) {
+            do {
+                mGSMTestHandler.wait();
+            } while (mGSMTestHandler.getGSMPhone() == null);
+        }
+
+        mGSMPhone = mGSMTestHandler.getGSMPhone();
+        mRadioControl = mGSMTestHandler.getSimulatedCommands();
+
+        mHandler = mGSMTestHandler.getHandler();
+        mGSMPhone.registerForPhoneStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null);
+        mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null);
+        mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
+
+        mGSMPhone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL, null);
+
+        mGSMPhone.registerForSuppServiceNotification(mHandler, EVENT_SSN, null);
+        mGSMPhone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
+        mGSMPhone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
+        mGSMPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null);
+
+        mGSMPhone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null);
+
+        // wait until we get phone in both voice and data service
+        Message msg;
+        ServiceState state;
+
+        do {
+            msg = mGSMTestHandler.waitForMessage(SERVICE_STATE_CHANGED);
+            assertNotNull("Message Time Out", msg);
+            state = (ServiceState) ((AsyncResult) msg.obj).result;
+        } while (state.getState() != ServiceState.STATE_IN_SERVICE);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mRadioControl.shutdown();
+
+        mGSMPhone.unregisterForPhoneStateChanged(mHandler);
+        mGSMPhone.unregisterForNewRingingConnection(mHandler);
+        mGSMPhone.unregisterForDisconnect(mHandler);
+        mGSMPhone.setOnPostDialCharacter(mHandler, 0, null);
+        mGSMPhone.unregisterForSuppServiceNotification(mHandler);
+        mGSMPhone.unregisterForMmiInitiate(mHandler);
+        mGSMPhone.unregisterForMmiComplete(mHandler);
+
+        mGSMPhone = null;
+        mRadioControl = null;
+        mHandler = null;
+        mGSMTestHandler.cleanup();
+
+        super.tearDown();
+    }
+
+    // These test can only be run once.
+    public int startPerformance(Intermediates intermediates) {
+        return 1;
+    }
+
+    public boolean isPerformanceOnly() {
+        return false;
+    }
+
+
+    //This test is causing the emulator screen to turn off. I don't understand
+    //why, but I'm removing it until we can figure it out.
+    public void brokenTestGeneral() throws Exception {
+        Connection cn;
+        Message msg;
+        AsyncResult ar;
+
+        // IDLE state
+
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+        assertFalse(mGSMPhone.canConference());
+
+        // One DIALING connection
+
+        mRadioControl.setAutoProgressConnectingCall(false);
+
+        mGSMPhone.dial("+13125551212");
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState());
+        assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        /*do {
+            mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+        } while (mGSMPhone.getForegroundCall().getConnections().size() == 0);*/
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.DIALING,
+                mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        cn = mGSMPhone.getForegroundCall().getConnections().get(0);
+        assertTrue(!cn.isIncoming());
+        assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState());
+
+        assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause());
+
+        assertFalse(mGSMPhone.canConference());
+
+        // One ALERTING connection
+
+        mRadioControl.progressConnectingCallState();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        }
+        while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ALERTING, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        cn = mGSMPhone.getForegroundCall().getConnections().get(0);
+        assertTrue(!cn.isIncoming());
+        assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState());
+        assertFalse(mGSMPhone.canConference());
+
+        // One ACTIVE connection
+
+        mRadioControl.progressConnectingCallState();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0);
+
+        cn = mGSMPhone.getForegroundCall().getConnections().get(0);
+        assertTrue(!cn.isIncoming());
+        assertEquals(Connection.PostDialState.COMPLETE, cn.getPostDialState());
+        assertFalse(mGSMPhone.canConference());
+
+        // One disconnected connection
+        mGSMPhone.getForegroundCall().hangup();
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0);
+
+        assertFalse(mGSMPhone.canConference());
+
+        cn = mGSMPhone.getForegroundCall().getEarliestConnection();
+
+        assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+        // Back to idle state
+
+        mGSMPhone.clearDisconnected();
+
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        assertFalse(mGSMPhone.canConference());
+
+        // cn left over from before phone.clearDisconnected();
+
+        assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+        // One ringing (INCOMING) call
+
+        mRadioControl.triggerRing("18005551212");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+        ar = (AsyncResult) msg.obj;
+        cn = (Connection) ar.result;
+        assertTrue(cn.isRinging());
+        assertEquals(mGSMPhone.getRingingCall(), cn.getCall());
+
+        assertEquals(1, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime());
+
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        cn = mGSMPhone.getRingingCall().getConnections().get(0);
+        assertTrue(cn.isIncoming());
+        assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState());
+
+        assertFalse(mGSMPhone.canConference());
+
+        // One mobile terminated active call
+        mGSMPhone.acceptCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getRingingCall().getConnections().size() == 1);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE,
+                mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0);
+
+        cn = mGSMPhone.getForegroundCall().getConnections().get(0);
+        assertTrue(cn.isIncoming());
+        assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState());
+
+        assertFalse(mGSMPhone.canConference());
+
+        // One disconnected (local hangup) call
+
+        try {
+            Connection conn;
+            conn = mGSMPhone.getForegroundCall().getConnections().get(0);
+            conn.hangup();
+        } catch (CallStateException ex) {
+            ex.printStackTrace();
+            fail("unexpected ex");
+        }
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.DISCONNECTED,
+                mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0);
+
+        cn = mGSMPhone.getForegroundCall().getEarliestConnection();
+
+        assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+        assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+
+        assertFalse(mGSMPhone.canConference());
+
+        // Back to idle state
+
+        mGSMPhone.clearDisconnected();
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+
+        assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        assertFalse(mGSMPhone.canConference());
+
+        // cn left over from before phone.clearDisconnected();
+
+        assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+        // One ringing call
+
+        mRadioControl.triggerRing("18005551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getRingingCall().getConnections().isEmpty());
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+        assertEquals(1, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime());
+
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        assertFalse(mGSMPhone.canConference());
+
+        // One rejected call
+        mGSMPhone.rejectCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.IDLE);
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+
+        assertEquals(1, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime());
+
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        cn = mGSMPhone.getRingingCall().getEarliestConnection();
+        assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+        assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
+
+        assertFalse(mGSMPhone.canConference());
+
+        // Back to idle state
+
+        mGSMPhone.clearDisconnected();
+
+        assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        assertFalse(mGSMPhone.canConference());
+        assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+        // One ringing call
+
+        mRadioControl.triggerRing("18005551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getRingingCall().getConnections().isEmpty());
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+        cn = mGSMPhone.getRingingCall().getEarliestConnection();
+
+        // Ringing call disconnects
+
+        mRadioControl.triggerHangupForeground();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.IDLE);
+
+        assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
+
+        // One Ringing Call
+
+        mRadioControl.triggerRing("18005551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+
+        cn = mGSMPhone.getRingingCall().getEarliestConnection();
+
+        // One answered call
+        mGSMPhone.acceptCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // one holding call
+        mGSMPhone.switchHoldingAndActive();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
+
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+        // one active call
+        mGSMPhone.switchHoldingAndActive();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        }
+        while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // One disconnected call in the foreground slot
+
+        mRadioControl.triggerHangupAll();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.IDLE);
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());
+
+        // Test missed calls
+
+        mRadioControl.triggerRing("18005551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+        mGSMPhone.rejectCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (msg.what != EVENT_DISCONNECT);
+
+        ar = (AsyncResult) msg.obj;
+        cn = (Connection) ar.result;
+
+        assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState());
+
+        // Test incoming not missed calls
+
+        mRadioControl.triggerRing("18005551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+        cn = mGSMPhone.getRingingCall().getEarliestConnection();
+
+        mGSMPhone.acceptCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+        assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause());
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+
+        try {
+            mGSMPhone.getForegroundCall().hangup();
+        } catch (CallStateException ex) {
+            ex.printStackTrace();
+            fail("unexpected ex");
+        }
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState()
+                != Call.State.DISCONNECTED);
+
+        assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+
+        //
+        // Test held and hangup held calls
+        //
+
+        // One ALERTING call
+        mGSMPhone.dial("+13125551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+        assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        mRadioControl.progressConnectingCallState();
+        mRadioControl.progressConnectingCallState();
+
+        // One ACTIVE call
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        // One ACTIVE call, one ringing call
+
+        mRadioControl.triggerRing("18005551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+        // One HOLDING call, one ACTIVE call
+        mGSMPhone.acceptCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+        assertTrue(mGSMPhone.canConference());
+
+        // Conference the two
+        mGSMPhone.conference();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertTrue(mGSMPhone.getForegroundCall().isMultiparty());
+        assertFalse(mGSMPhone.canConference());
+
+        // Hold the multiparty call
+        mGSMPhone.switchHoldingAndActive();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        }
+        while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING);
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertTrue(mGSMPhone.getBackgroundCall().isMultiparty());
+        assertFalse(mGSMPhone.canConference());
+
+        // Multiparty call on hold, call waiting added
+
+        mRadioControl.triggerRing("18005558355");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+        assertTrue(mGSMPhone.getBackgroundCall().isMultiparty());
+        assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+        assertFalse(mGSMPhone.canConference());
+
+        // Hangup conference call, ringing call still around
+        mGSMPhone.getBackgroundCall().hangup();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED);
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState());
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+        // Reject waiting call
+        mGSMPhone.rejectCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.IDLE);
+
+        assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+    }
+
+    public void testOutgoingCallFailImmediately() throws Exception {
+        Message msg;
+
+        // Test outgoing call fail-immediately edge case
+        // This happens when a call terminated before ever appearing in a
+        // call list
+        // This should land the immediately-failing call in the
+        // ForegroundCall list as an IDLE call
+        mRadioControl.setNextDialFailImmediately(true);
+
+        Connection cn = mGSMPhone.dial("+13125551212");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+    }
+
+    public void testHangupOnOutgoing() throws Exception {
+        Connection cn;
+        Message msg;
+
+        mRadioControl.setAutoProgressConnectingCall(false);
+
+        // Test 1: local hangup in "DIALING" state
+        mGSMPhone.dial("+13125551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        }
+        while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING);
+
+        cn = mGSMPhone.getForegroundCall().getEarliestConnection();
+
+        mGSMPhone.getForegroundCall().hangup();
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+
+        // Test 2: local hangup in "ALERTING" state
+        mGSMPhone.dial("+13125551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+        mRadioControl.progressConnectingCallState();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        }
+        while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING);
+
+        cn = mGSMPhone.getForegroundCall().getEarliestConnection();
+
+        mGSMPhone.getForegroundCall().hangup();
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+
+        // Test 3: local immediate hangup before GSM index is
+        // assigned (CallTracker.hangupPendingMO case)
+
+        mRadioControl.pauseResponses();
+
+        cn = mGSMPhone.dial("+13125551212");
+
+        cn.hangup();
+
+        mRadioControl.resumeResponses();
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+
+        assertEquals(Connection.DisconnectCause.LOCAL,
+                mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause());
+    }
+
+    public void testHangupOnChannelClose() throws Exception {
+        mGSMPhone.dial("+13125551212");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getConnections().isEmpty());
+
+        mRadioControl.shutdown();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+            mGSMPhone.clearDisconnected();
+        } while (!mGSMPhone.getForegroundCall().getConnections().isEmpty());
+    }
+
+    public void testIncallMmiCallDeflection() throws Exception {
+        Message msg;
+
+        // establish an active call
+        mGSMPhone.dial("+13125551212");
+
+        do {
+            mRadioControl.progressConnectingCallState();
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // establish a ringing (WAITING) call
+
+        mRadioControl.triggerRing("18005551212");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // Simulate entering 0 followed by SEND: release all held calls
+        // or sets UDUB for a waiting call.
+        mGSMPhone.handleInCallMmiCommands("0");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // change the active call to holding call
+        mGSMPhone.switchHoldingAndActive();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
+
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+        // Simulate entering 0 followed by SEND: release all held calls
+        // or sets UDUB for a waiting call.
+        mGSMPhone.handleInCallMmiCommands("0");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING);
+
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState());
+    }
+
+    public void testIncallMmiCallWaiting() throws Exception {
+        Message msg;
+
+        // establish an active call
+        mGSMPhone.dial("+13125551212");
+
+        do {
+            mRadioControl.progressConnectingCallState();
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // establish a ringing (WAITING) call
+
+        mRadioControl.triggerRing("18005551212");
+
+        do {
+            msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+            assertNotNull("Message Time Out", msg);
+        } while (msg.what != EVENT_RINGING);
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // Simulate entering 1 followed by SEND: release all active calls
+        // (if any exist) and accepts the other (held or waiting) call.
+
+        mGSMPhone.handleInCallMmiCommands("1");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals("18005551212",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+
+        // change the active call to holding call
+        mGSMPhone.switchHoldingAndActive();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+        // Simulate entering 1 followed by SEND: release all active calls
+        // (if any exist) and accepts the other (held or waiting) call.
+        mGSMPhone.handleInCallMmiCommands("1");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+        assertEquals("18005551212",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+
+        // at this point, the active call with number==18005551212 should
+        // have the gsm index of 2
+
+        mRadioControl.triggerRing("16505550100");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // Simulate entering "12" followed by SEND: release the call with
+        // gsm index equals to 2.
+        mGSMPhone.handleInCallMmiCommands("12");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        mGSMPhone.acceptCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // at this point, the call with number==16505550100 should
+        // have the gsm index of 1
+        mGSMPhone.dial("+13125551212");
+
+        do {
+            mRadioControl.progressConnectingCallState();
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE ||
+                mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+        // at this point, the active call with number==13125551212 should
+        // have the gsm index of 2
+
+        // Simulate entering "11" followed by SEND: release the call with
+        // gsm index equals to 1. This should not be allowed, and a
+        // Supplementary Service notification must be received.
+        mGSMPhone.handleInCallMmiCommands("11");
+
+        msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED);
+        assertNotNull("Message Time Out", msg);
+        assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null);
+
+        // Simulate entering "12" followed by SEND: release the call with
+        // gsm index equals to 2.
+        mGSMPhone.handleInCallMmiCommands("12");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+        // Simulate entering 1 followed by SEND: release all active calls
+        // (if any exist) and accepts the other (held or waiting) call.
+        mGSMPhone.handleInCallMmiCommands("1");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+        assertEquals("16505550100",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+
+        // Simulate entering "11" followed by SEND: release the call with
+        // gsm index equals to 1.
+        mGSMPhone.handleInCallMmiCommands("11");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+    }
+
+    public void testIncallMmiCallHold() throws Exception {
+        Message msg;
+
+        // establish an active call
+        mGSMPhone.dial("13125551212");
+
+        do {
+            mRadioControl.progressConnectingCallState();
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // establish a ringing (WAITING) call
+
+        mRadioControl.triggerRing("18005551212");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // simulate entering 2 followed by SEND: place all active calls
+        // (if any exist) on hold and accepts the other (held or waiting)
+        // call
+
+        mGSMPhone.handleInCallMmiCommands("2");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
+
+
+        assertFalse(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE,
+                mGSMPhone.getForegroundCall().getState());
+        assertEquals("18005551212",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+        assertEquals("13125551212",
+                mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress());
+
+        // swap the active and holding calls
+        mGSMPhone.handleInCallMmiCommands("2");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals("13125551212",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+        assertEquals("18005551212",
+                mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress());
+
+        // merge the calls
+        mGSMPhone.conference();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+        assertEquals(2, mGSMPhone.getForegroundCall().getConnections().size());
+
+        // at this point, we have an active conference call, with
+        // call(1) = 13125551212 and call(2) = 18005551212
+
+        // Simulate entering "23" followed by SEND: places all active call
+        // on hold except call 3. This should fail and a supplementary service
+        // failed notification should be received.
+
+        mGSMPhone.handleInCallMmiCommands("23");
+
+        msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED);
+        assertNotNull("Message Time Out", msg);
+        assertFalse("IncallMmiCallHold: separate should have failed!", msg == null);
+
+        // Simulate entering "21" followed by SEND: places all active call
+        // on hold except call 1.
+        mGSMPhone.handleInCallMmiCommands("21");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals("13125551212",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+        assertEquals("18005551212",
+                mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress());
+    }
+
+    public void testIncallMmiMultipartyServices() throws Exception {
+        // establish an active call
+        mGSMPhone.dial("13125551212");
+
+        do {
+            mRadioControl.progressConnectingCallState();
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        // dial another call
+        mGSMPhone.dial("18005551212");
+
+        do {
+            mRadioControl.progressConnectingCallState();
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+        mGSMPhone.handleInCallMmiCommands("3");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+        assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals("18005551212",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+        assertEquals("13125551212",
+                mGSMPhone.getForegroundCall().getConnections().get(1).getAddress());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+    }
+
+    public void testCallIndex() throws Exception {
+        Message msg;
+
+        // establish the first call
+        mGSMPhone.dial("16505550100");
+
+        do {
+            mRadioControl.progressConnectingCallState();
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        String baseNumber = "1650555010";
+
+        for (int i = 1; i < 6; i++) {
+            String number = baseNumber + i;
+
+            mGSMPhone.dial(number);
+
+            do {
+                mRadioControl.progressConnectingCallState();
+                assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+            } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+            assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+            assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+            if (mGSMPhone.getBackgroundCall().getConnections().size() >= 5) {
+                break;
+            }
+
+            mGSMPhone.conference();
+
+            do {
+                assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+            } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+            assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+            assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+        }
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals("16505550105",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+        // create an incoming call, this call should have the call index
+        // of 7
+        mRadioControl.triggerRing("18005551212");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+        assertNotNull("Message Time Out", msg);
+
+        assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+        assertTrue(mGSMPhone.getRingingCall().isRinging());
+        assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+        // hangup the background call and accept the ringing call
+        mGSMPhone.getBackgroundCall().hangup();
+        mGSMPhone.acceptCall();
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals("18005551212",
+                mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+        assertEquals("16505550105",
+                mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress());
+
+        mGSMPhone.handleInCallMmiCommands("17");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+        assertEquals("16505550105",
+                mGSMPhone.getBackgroundCall().getConnections().get(0).
+                        getAddress());
+
+        mGSMPhone.handleInCallMmiCommands("1");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+        assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        mGSMPhone.handleInCallMmiCommands("16");
+
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+    }
+
+    public void testPostDialSequences() throws Exception {
+        Message msg;
+        AsyncResult ar;
+        Connection cn;
+
+        mGSMPhone.dial("+13125551212,1234;5N8xx");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        ar = (AsyncResult) (msg.obj);
+        cn = (Connection) (ar.result);
+        assertEquals(',', msg.arg1);
+        assertEquals("1234;5N8", cn.getRemainingPostDialString());
+
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals('1', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals('2', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals('3', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals('4', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(';', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        cn = (Connection) (ar.result);
+        assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState());
+        assertEquals(Connection.PostDialState.WAIT, ar.userObj);
+        cn.proceedAfterWaitChar();
+
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals('5', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertEquals('N', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        cn = (Connection) (ar.result);
+        assertEquals(Connection.PostDialState.WILD, cn.getPostDialState());
+        assertEquals(Connection.PostDialState.WILD, ar.userObj);
+        cn.proceedAfterWildChar(",6;7");
+
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        ar = (AsyncResult) (msg.obj);
+        cn = (Connection) (ar.result);
+        assertEquals(',', msg.arg1);
+        assertEquals("6;78", cn.getRemainingPostDialString());
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals('6', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(';', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        cn = (Connection) (ar.result);
+        assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState());
+        assertEquals(Connection.PostDialState.WAIT, ar.userObj);
+        cn.proceedAfterWaitChar();
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals('7', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals('8', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+        // Bogus chars at end should be ignored
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(0, msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        cn = (Connection) (ar.result);
+        assertEquals(Connection.PostDialState.COMPLETE,
+                cn.getPostDialState());
+        assertEquals(Connection.PostDialState.COMPLETE, ar.userObj);
+    }
+
+    public void testPostDialCancel() throws Exception {
+        Message msg;
+        AsyncResult ar;
+        Connection cn;
+
+        mGSMPhone.dial("+13125551212,N");
+        mRadioControl.progressConnectingToActive();
+
+        mRadioControl.progressConnectingToActive();
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(',', msg.arg1);
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+        assertEquals('N', msg.arg1);
+        ar = (AsyncResult) (msg.obj);
+        cn = (Connection) (ar.result);
+        assertEquals(Connection.PostDialState.WILD, cn.getPostDialState());
+        cn.cancelPostDial();
+
+        assertEquals(Connection.PostDialState.CANCELLED, cn.getPostDialState());
+    }
+
+    public void testOutgoingCallFail() throws Exception {
+        Message msg;
+        /*
+        * normal clearing
+        */
+
+        mRadioControl.setNextCallFailCause(CallFailCause.NORMAL_CLEARING);
+        mRadioControl.setAutoProgressConnectingCall(false);
+
+        Connection cn = mGSMPhone.dial("+13125551212");
+
+        mRadioControl.progressConnectingCallState();
+
+        // I'm just progressing the call state to
+        // ensure getCurrentCalls() gets processed...
+        // Normally these failure conditions would happen in DIALING
+        // not ALERTING
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (cn.getState() == Call.State.DIALING);
+
+
+        mRadioControl.triggerHangupAll();
+        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        /*
+        * busy
+        */
+
+        mRadioControl.setNextCallFailCause(CallFailCause.USER_BUSY);
+        mRadioControl.setAutoProgressConnectingCall(false);
+
+        cn = mGSMPhone.dial("+13125551212");
+
+        mRadioControl.progressConnectingCallState();
+
+        // I'm just progressing the call state to
+        // ensure getCurrentCalls() gets processed...
+        // Normally these failure conditions would happen in DIALING
+        // not ALERTING
+        do {
+            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+        } while (cn.getState() == Call.State.DIALING);
+
+
+        mRadioControl.triggerHangupAll();
+        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+        assertNotNull("Message Time Out", msg);
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(Connection.DisconnectCause.BUSY, cn.getDisconnectCause());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.DISCONNECTED,
+                mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+        /*
+        * congestion
+        */
+
+        mRadioControl.setNextCallFailCause(CallFailCause.NO_CIRCUIT_AVAIL);
+        mRadioControl.setAutoProgressConnectingCall(false);
+
+        cn = mGSMPhone.dial("+13125551212");
+
+        mRadioControl.progressConnectingCallState();
+
+        // I'm just progressing the call state to
+        // ensure getCurrentCalls() gets processed...
+        // Normally these failure conditions would happen in DIALING
+        // not ALERTING
+        do {
+            msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+            assertNotNull("Message Time Out", msg);
+        } while (cn.getState() == Call.State.DIALING);
+
+
+        mRadioControl.triggerHangupAll();
+
+        // Unlike the while loops above, this one waits
+        // for a "phone state changed" message back to "idle"
+        do {
+            msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+            assertNotNull("Message Time Out", msg);
+        } while (!(msg.what == EVENT_PHONE_STATE_CHANGED
+                && mGSMPhone.getState() == Phone.State.IDLE));
+
+        assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+        assertEquals(Connection.DisconnectCause.CONGESTION, cn.getDisconnectCause());
+
+        assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+        assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+        assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+        assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+        assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+        assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+        assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+    }
+
+    public void testSSNotification() throws Exception {
+        // MO
+        runTest(0, SuppServiceNotification.MO_CODE_UNCONDITIONAL_CF_ACTIVE);
+        runTest(0, SuppServiceNotification.MO_CODE_CALL_IS_WAITING);
+        runTest(0, SuppServiceNotification.MO_CODE_CALL_DEFLECTED);
+
+        // MT
+        runTest(1, SuppServiceNotification.MT_CODE_FORWARDED_CALL);
+        runTest(1, SuppServiceNotification.MT_CODE_CALL_CONNECTED_ECT);
+        runTest(1, SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED);
+    }
+
+    private void runTest(int type, int code) {
+        Message msg;
+
+        mRadioControl.triggerSsn(type, code);
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_SSN);
+        assertNotNull("Message Time Out", msg);
+        AsyncResult ar = (AsyncResult) msg.obj;
+
+        assertNull(ar.exception);
+
+        SuppServiceNotification notification =
+                (SuppServiceNotification) ar.result;
+
+        assertEquals(type, notification.notificationType);
+        assertEquals(code, notification.code);
+    }
+
+    public void testUssd() throws Exception {
+        // Quick hack to work around a race condition in this test:
+        // We may initiate a USSD MMI before GSMPhone receives its initial
+        // GSMTestHandler.EVENT_RADIO_OFF_OR_NOT_AVAILABLE event.  When the phone sees this
+        // event, it will cancel the just issued USSD MMI, which we don't
+        // want.  So sleep a little first.
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException ex) {
+            // do nothing
+        }
+
+        verifyNormal();
+        verifyCancel();
+        varifyNetworkInitiated();
+    }
+
+    private void varifyNetworkInitiated() {
+        Message msg;
+        AsyncResult ar;
+        MmiCode mmi;
+
+        // Receive an incoming NOTIFY
+        mRadioControl.triggerIncomingUssd("0", "NOTIFY message");
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+        assertNotNull("Message Time Out", msg);
+        ar = (AsyncResult) msg.obj;
+        mmi = (MmiCode) ar.result;
+
+        assertFalse(mmi.isUssdRequest());
+
+        // Receive a REQUEST and send response
+        mRadioControl.triggerIncomingUssd("1", "REQUEST Message");
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+        assertNotNull("Message Time Out", msg);
+        ar = (AsyncResult) msg.obj;
+        mmi = (MmiCode) ar.result;
+
+        assertTrue(mmi.isUssdRequest());
+
+        mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding...");
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+        assertNotNull("Message Time Out", msg);
+        ar = (AsyncResult) msg.obj;
+        mmi = (MmiCode) ar.result;
+
+        GsmMmiCode gsmMmi = (GsmMmiCode) mmi;
+        assertTrue(gsmMmi.isPendingUSSD());
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+        assertNotNull("Message Time Out", msg);
+        ar = (AsyncResult) msg.obj;
+        mmi = (MmiCode) ar.result;
+
+        assertNull(ar.exception);
+        assertFalse(mmi.isUssdRequest());
+
+        // Receive a REQUEST and cancel
+        mRadioControl.triggerIncomingUssd("1", "REQUEST Message");
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+        assertNotNull("Message Time Out", msg);
+        ar = (AsyncResult) msg.obj;
+        mmi = (MmiCode) ar.result;
+
+        assertTrue(mmi.isUssdRequest());
+
+        mmi.cancel();
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+        assertNotNull("Message Time Out", msg);
+
+        ar = (AsyncResult) msg.obj;
+        mmi = (MmiCode) ar.result;
+
+        assertNull(ar.exception);
+        assertEquals(MmiCode.State.CANCELLED, mmi.getState());
+
+        List mmiList = mGSMPhone.getPendingMmiCodes();
+        assertEquals(0, mmiList.size());
+    }
+
+    private void verifyNormal() throws CallStateException {
+        Message msg;
+        AsyncResult ar;
+        MmiCode mmi;
+
+        mGSMPhone.dial("#646#");
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+        assertNotNull("Message Time Out", msg);
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+        assertNotNull("Message Time Out", msg);
+
+        ar = (AsyncResult) msg.obj;
+        mmi = (MmiCode) ar.result;
+        assertEquals(MmiCode.State.COMPLETE, mmi.getState());
+    }
+
+
+    private void verifyCancel() throws CallStateException {
+        /**
+         * This case makes an assumption that dial() will add the USSD
+         * to the "pending MMI codes" list before it returns.  This seems
+         * like reasonable semantics. It also assumes that the USSD
+         * request in question won't complete until we get back to the
+         * event loop, thus cancel() is safe.
+         */
+        Message msg;
+
+        mGSMPhone.dial("#646#");
+
+        List<? extends MmiCode> pendingMmis = mGSMPhone.getPendingMmiCodes();
+
+        assertEquals(1, pendingMmis.size());
+
+        MmiCode mmi = pendingMmis.get(0);
+        assertTrue(mmi.isCancelable());
+        mmi.cancel();
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+        assertNotNull("Message Time Out", msg);
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+        assertNotNull("Message Time Out", msg);
+
+        AsyncResult ar = (AsyncResult) msg.obj;
+        mmi = (MmiCode) ar.result;
+
+        assertEquals(MmiCode.State.CANCELLED, mmi.getState());
+    }
+
+    public void testRilHooks() throws Exception {
+        //
+        // These test cases all assume the RIL OEM hooks
+        // just echo back their input
+        //
+
+        Message msg;
+        AsyncResult ar;
+
+        // null byte array
+
+        mGSMPhone.invokeOemRilRequestRaw(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+        assertNotNull("Message Time Out", msg);
+
+        ar = ((AsyncResult) msg.obj);
+
+        assertNull(ar.result);
+        assertNull(ar.exception);
+
+        // empty byte array
+
+        mGSMPhone.invokeOemRilRequestRaw(new byte[0], mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+        assertNotNull("Message Time Out", msg);
+
+        ar = ((AsyncResult) msg.obj);
+
+        assertEquals(0, ((byte[]) (ar.result)).length);
+        assertNull(ar.exception);
+
+        // byte array with data
+
+        mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"),
+                mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+        assertNotNull("Message Time Out", msg);
+
+        ar = ((AsyncResult) msg.obj);
+
+        assertEquals("Hello", new String(((byte[]) (ar.result)), "utf-8"));
+        assertNull(ar.exception);
+
+        // null strings
+
+        mGSMPhone.invokeOemRilRequestStrings(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+        assertNotNull("Message Time Out", msg);
+
+        ar = ((AsyncResult) msg.obj);
+
+        assertNull(ar.result);
+        assertNull(ar.exception);
+
+        // empty byte array
+
+        mGSMPhone.invokeOemRilRequestStrings(new String[0],
+                mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+        assertNotNull("Message Time Out", msg);
+
+        ar = ((AsyncResult) msg.obj);
+
+        assertEquals(0, ((String[]) (ar.result)).length);
+        assertNull(ar.exception);
+
+        // Strings with data
+
+        String s[] = new String[1];
+
+        s[0] = "Hello";
+
+        mGSMPhone.invokeOemRilRequestStrings(s, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+        assertNotNull("Message Time Out", msg);
+
+        ar = ((AsyncResult) msg.obj);
+
+        assertEquals("Hello", ((String[]) (ar.result))[0]);
+        assertEquals(1, ((String[]) (ar.result)).length);
+        assertNull(ar.exception);
+    }
+
+    public void testMmi() throws Exception {
+        mRadioControl.setAutoProgressConnectingCall(false);
+
+        // "valid" MMI sequences
+        runValidMmi("*#67#", false);
+        runValidMmi("##43*11#", false);
+        runValidMmi("#33*1234*11#", false);
+        runValidMmi("*21*6505551234**5#", false);
+        runValidMmi("**03**1234*4321*4321#", false);
+        // pound string
+        runValidMmi("5308234092307540923#", true);
+        // short code
+        runValidMmi("22", true);
+        // as part of call setup
+        runValidMmiWithConnect("*31#6505551234");
+
+        // invalid MMI sequences
+        runNotMmi("6505551234");
+        runNotMmi("1234#*12#34566654");
+        runNotMmi("*#*#12#*");
+    }
+
+    private void runValidMmi(String dialString, boolean cancelable) throws CallStateException {
+        Connection c = mGSMPhone.dial(dialString);
+        assertNull(c);
+        Message msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+        assertNotNull("Message Time Out", msg);
+        // Should not be cancelable.
+        AsyncResult ar = (AsyncResult) msg.obj;
+        MmiCode mmi = (MmiCode) ar.result;
+        assertEquals(cancelable, mmi.isCancelable());
+
+        msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+        assertNotNull("Message Time Out", msg);
+    }
+
+    private void runValidMmiWithConnect(String dialString) throws CallStateException {
+        mRadioControl.pauseResponses();
+
+        Connection c = mGSMPhone.dial(dialString);
+        assertNotNull(c);
+
+        hangup(c);
+    }
+
+    private void hangup(Connection cn) throws CallStateException {
+        cn.hangup();
+
+        mRadioControl.resumeResponses();
+        assertNotNull(mGSMTestHandler.waitForMessage(EVENT_DISCONNECT));
+
+    }
+
+    private void runNotMmi(String dialString) throws CallStateException {
+        mRadioControl.pauseResponses();
+
+        Connection c = mGSMPhone.dial(dialString);
+        assertNotNull(c);
+
+        hangup(c);
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java
new file mode 100644
index 0000000..fb8a5d9
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 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.internal.telephony.gsm;
+
+import android.content.Context;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.test.SimulatedCommands;
+import com.android.internal.telephony.TestPhoneNotifier;
+
+/**
+ * This class creates a HandlerThread which waits for the various messages.
+ */
+public class GSMTestHandler extends HandlerThread implements Handler.Callback {
+
+    private Handler mHandler;
+    private Message mCurrentMessage;
+
+    private Boolean mMsgConsumed;
+    private SimulatedCommands sc;
+    private GSMPhone mGSMPhone;
+    private Context mContext;
+
+    private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000;
+
+    public GSMTestHandler(Context context) {
+        super("GSMPhoneTest");
+        mMsgConsumed = false;
+        mContext = context;
+   }
+
+    @Override
+    protected void onLooperPrepared() {
+        sc = new SimulatedCommands();
+        mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true);
+        mHandler = new Handler(getLooper(), this);
+        synchronized (this) {
+            notifyAll();
+        }
+    }
+
+    public boolean handleMessage(Message msg) {
+        synchronized (this) {
+            mCurrentMessage = msg;
+            this.notifyAll();
+            while(!mMsgConsumed) {
+                try {
+                    this.wait();
+                } catch (InterruptedException e) {}
+            }
+            mMsgConsumed = false;
+        }
+        return true;
+    }
+
+
+    public void cleanup() {
+        Looper looper = getLooper();
+        if (looper != null) looper.quit();
+        mHandler = null;
+    }
+
+    public Handler getHandler() {
+        return mHandler;
+    }
+
+    public SimulatedCommands getSimulatedCommands() {
+        return sc;
+    }
+
+    public GSMPhone getGSMPhone() {
+        return mGSMPhone;
+    }
+
+    public Message waitForMessage(int code) {
+        Message msg;
+        while(true) {
+            msg = null;
+            synchronized (this) {
+                try {
+                    this.wait(FAIL_TIMEOUT_MILLIS);
+                } catch (InterruptedException e) {
+                }
+
+                // Check if timeout has occurred.
+                if (mCurrentMessage != null) {
+                    // Consume the message
+                    msg = Message.obtain();
+                    msg.copyFrom(mCurrentMessage);
+                    mCurrentMessage = null;
+                    mMsgConsumed = true;
+                    this.notifyAll();
+                }
+            }
+            if (msg == null || code == GSMPhoneTest.ANY_MESSAGE || msg.what == code) return msg;
+       }
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java
new file mode 100644
index 0000000..f36d96b
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import junit.framework.TestCase;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+public class GsmAlphabetTest extends TestCase {
+
+    private static final String sGsmExtendedChars = "{|}\\[~]\f\u20ac";
+
+    @SmallTest
+    public void test7bitWithHeader() throws Exception {
+        byte[] data = new byte[3];
+        data[0] = (byte) 1;
+        data[1] = (byte) 2;
+        data[2] = (byte) 2;
+        SmsHeader header = new SmsHeader();
+        header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data));
+
+        String message = "aaaaaaaaaabbbbbbbbbbcccccccccc"; 
+        byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header.toByteArray());
+        int septetCount = GsmAlphabet.countGsmSeptets(message, false);
+        String parsedMessage = GsmAlphabet.gsm7BitPackedToString(
+                userData, header.toByteArray().length+1, septetCount, 1);
+        assertEquals(message, parsedMessage);
+    }
+
+    // TODO: This method should *really* be a series of individual test methods.
+    @LargeTest
+    public void testBasic() throws Exception {
+        // '@' maps to char 0
+        assertEquals(0, GsmAlphabet.charToGsm('@'));
+
+        // `a (a with grave accent) maps to last GSM charater
+        assertEquals(0x7f, GsmAlphabet.charToGsm('\u00e0'));
+
+        //
+        // These are the extended chars
+        // They should all return GsmAlphabet.GSM_EXTENDED_ESCAPE
+        //
+
+        for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) {
+            assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE,
+                    GsmAlphabet.charToGsm(sGsmExtendedChars.charAt(i)));
+
+        }
+
+        // euro symbol
+        assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE,
+                GsmAlphabet.charToGsm('\u20ac'));
+
+        // An unmappable char (the 'cent' char) maps to a space
+        assertEquals(GsmAlphabet.charToGsm(' '),
+                GsmAlphabet.charToGsm('\u00a2'));
+
+        // unmappable = space = 1 septet
+        assertEquals(1, GsmAlphabet.countGsmSeptets('\u00a2'));
+
+        //
+        // Test extended table
+        //
+
+        for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) {
+            assertEquals(sGsmExtendedChars.charAt(i),
+                    GsmAlphabet.gsmExtendedToChar(
+                            GsmAlphabet.charToGsmExtended(sGsmExtendedChars.charAt(i))));
+
+        }
+
+        // Unmappable extended char
+        assertEquals(GsmAlphabet.charToGsm(' '),
+                GsmAlphabet.charToGsmExtended('@'));
+
+        //
+        // gsmToChar()
+        //
+
+        assertEquals('@', GsmAlphabet.gsmToChar(0));
+
+        // `a (a with grave accent) maps to last GSM charater
+        assertEquals('\u00e0', GsmAlphabet.gsmToChar(0x7f));
+
+        assertEquals('\uffff',
+                GsmAlphabet.gsmToChar(GsmAlphabet.GSM_EXTENDED_ESCAPE));
+
+        // Out-of-range/unmappable value
+        assertEquals(' ', GsmAlphabet.gsmToChar(0x80));
+
+        //
+        // gsmExtendedToChar()
+        //
+
+        assertEquals('{', GsmAlphabet.gsmExtendedToChar(0x28));
+
+        // No double-escapes
+        assertEquals(' ', GsmAlphabet.gsmExtendedToChar(
+                GsmAlphabet.GSM_EXTENDED_ESCAPE));
+
+        // Unmappable
+        assertEquals(' ', GsmAlphabet.gsmExtendedToChar(0));
+
+        //
+        // stringTo7BitPacked, gsm7BitPackedToString
+        //
+
+        byte[] packed;
+        StringBuilder testString = new StringBuilder(300);
+
+        // Check all alignment cases
+        for (int i = 0; i < 9; i++, testString.append('@')) {
+            packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+            assertEquals(testString.toString(),
+                    GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+        }
+
+        // Check full non-extended alphabet
+        for (int i = 0; i < 0x80; i++) {
+            char c;
+
+            if (i == GsmAlphabet.GSM_EXTENDED_ESCAPE) {
+                continue;
+            }
+
+            c = GsmAlphabet.gsmToChar(i);
+            testString.append(c);
+
+            // These are all non-extended chars, so it should be
+            // one septet per char
+            assertEquals(1, GsmAlphabet.countGsmSeptets(c));
+        }
+
+        packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+        assertEquals(testString.toString(),
+                GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+
+        // Test extended chars too
+
+        testString.append(sGsmExtendedChars);
+
+        for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) {
+            // These are all extended chars, so it should be
+            // two septets per char
+            assertEquals(2, GsmAlphabet.countGsmSeptets(sGsmExtendedChars.charAt(i)));
+
+        }
+
+        packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+        assertEquals(testString.toString(),
+                GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+
+        // stringTo7BitPacked handles up to 255 septets
+
+        testString.setLength(0);
+        for (int i = 0; i < 255; i++) {
+            testString.append('@');
+        }
+
+        packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+        assertEquals(testString.toString(),
+                GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+
+        // > 255 septets throws runtime exception
+        testString.append('@');
+
+        try {
+            GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+            fail("expected exception");
+        } catch (EncodeException ex) {
+            // exception expected
+        }
+
+        // Try 254 septets with 127 extended chars
+
+        testString.setLength(0);
+        for (int i = 0; i < (255 / 2); i++) {
+            testString.append('{');
+        }
+
+        packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+        assertEquals(testString.toString(),
+                GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+
+        // > 255 septets throws runtime exception
+        testString.append('{');
+
+        try {
+            GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+            fail("expected exception");
+        } catch (EncodeException ex) {
+            // exception expected
+        }
+
+        //
+        // 8 bit unpacked format
+        //
+        // Note: we compare hex strings here
+        // because Assert doesnt have array-comparisons
+
+        byte unpacked[];
+
+        unpacked = SimUtils.hexStringToBytes("566F696365204D61696C");
+        assertEquals("Voice Mail",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+        assertEquals(SimUtils.bytesToHexString(unpacked),
+                SimUtils.bytesToHexString(
+                        GsmAlphabet.stringToGsm8BitPacked("Voice Mail")));
+
+        unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars);
+        // two bytes for every extended char
+        assertEquals(2 * sGsmExtendedChars.length(), unpacked.length);
+        assertEquals(sGsmExtendedChars,
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+        // should be two bytes per extended char
+        assertEquals(2 * sGsmExtendedChars.length(), unpacked.length);
+
+        // Test truncation of unaligned extended chars
+        unpacked = new byte[3];
+        GsmAlphabet.stringToGsm8BitUnpackedField(sGsmExtendedChars, unpacked,
+                0, unpacked.length);
+
+        // Should be one extended char and an 0xff at the end
+
+        assertEquals(0xff, 0xff & unpacked[2]);
+        assertEquals(sGsmExtendedChars.substring(0, 1),
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+        // Test truncation of normal chars
+        unpacked = new byte[3];
+        GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked,
+                0, unpacked.length);
+
+        assertEquals("abc",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+        // Test truncation of mixed normal and extended chars
+        unpacked = new byte[3];
+        GsmAlphabet.stringToGsm8BitUnpackedField("a{cd", unpacked,
+                0, unpacked.length);
+
+        assertEquals("a{",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+        // Test padding after normal char
+        unpacked = new byte[3];
+        GsmAlphabet.stringToGsm8BitUnpackedField("a", unpacked,
+                0, unpacked.length);
+
+        assertEquals("a",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+        assertEquals(0xff, 0xff & unpacked[1]);
+        assertEquals(0xff, 0xff & unpacked[2]);
+
+        // Test malformed input -- escape char followed by end of field
+        unpacked[0] = 0;
+        unpacked[1] = 0;
+        unpacked[2] = GsmAlphabet.GSM_EXTENDED_ESCAPE;
+
+        assertEquals("@@",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+        // non-zero offset
+        assertEquals("@",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
+
+        // test non-zero offset
+        unpacked[0] = 0;
+        GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked,
+                1, unpacked.length - 1);
+
+
+        assertEquals(0, unpacked[0]);
+
+        assertEquals("ab",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
+
+        // test non-zero offset with truncated extended char
+        unpacked[0] = 0;
+
+        GsmAlphabet.stringToGsm8BitUnpackedField("a{", unpacked,
+                1, unpacked.length - 1);
+
+        assertEquals(0, unpacked[0]);
+
+        assertEquals("a",
+                GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
+    }
+}
+
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java
new file mode 100644
index 0000000..6db230f
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 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.internal.telephony.gsm;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import com.android.internal.telephony.TestPhoneNotifier;
+import com.android.internal.telephony.test.SimulatedCommands;
+import com.android.internal.telephony.test.SimulatedRadioControl;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.telephony.gsm.SmsMessage;
+
+import java.util.Iterator;
+
+/**
+ * {@hide}
+ */
+public class SMSDispatcherTest extends AndroidTestCase {
+    @MediumTest
+    public void testCMT1() throws Exception {
+        SmsMessage sms;
+        SmsHeader header;
+        Iterator<SmsHeader.Element> elements;
+
+        String[] lines = new String[2];
+
+        lines[0] = "+CMT: ,158";
+        lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B"
+                 + "8423F000035502010106276170706C69636174696F6E2F766E642E776170"
+                 + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F"
+                 + "7547514D4141424C3641414141536741415A4B554141414141008D908918"
+                 + "802B31363530323438363137392F545950453D504C4D4E008A808E028000"
+                 + "88058103093A8083687474703A2F2F36";
+
+        sms = SmsMessage.newFromCMT(lines);
+        header = sms.getUserDataHeader();
+        assertNotNull(header);
+        assertNotNull(sms.getUserData());
+
+        elements = header.getElements().iterator();
+        assertNotNull(elements);
+    }
+
+    @MediumTest
+    public void testCMT2() throws Exception {
+        SmsMessage sms;
+        SmsHeader header;
+        Iterator<SmsHeader.Element> elements;
+
+        String[] lines = new String[2];
+
+
+        lines[0] = "+CMT: ,77";
+        lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F"
+                 + "00003550202362E3130322E3137312E3135302F524F347839776F7547514D4141"
+                 + "424C3641414141536741415A4B55414141414100";
+
+        sms = SmsMessage.newFromCMT(lines);
+        header = sms.getUserDataHeader();
+        System.out.println("header = " + header);
+        assertNotNull(header);
+        assertNotNull(sms.getUserData());
+
+        elements = header.getElements().iterator();
+        assertNotNull(elements);
+    }
+
+    @MediumTest
+    public void testEfRecord() throws Exception {
+        SmsMessage sms;
+
+        String s = "03029111000c9194981492631000f269206190022000a053e4534a05358bd3"
+                 + "69f05804259da0219418a40641536a110a0aea408080604028180e888462c1"
+                 + "50341c0f484432a1542c174c46b3e1743c9f9068442a994ea8946ac56ab95e"
+                 + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874"
+                 + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb"
+                 + "eff8bc7ecfeffbffffffffffffffffffffffffffff";
+       byte[] data = SimUtils.hexStringToBytes(s);
+
+       sms = SmsMessage.createFromEfRecord(1, data);
+       assertNotNull(sms.getMessageBody());
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java
new file mode 100644
index 0000000..db55bca
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.os.ServiceManager;
+import android.test.suitebuilder.annotation.Suppress;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+@Suppress
+public class SimPhoneBookTest extends TestCase {
+
+    public void testBasic() throws Exception {
+        ISimPhoneBook simPhoneBook =
+                ISimPhoneBook.Stub.asInterface(ServiceManager.getService("simphonebook"));
+        assertNotNull(simPhoneBook);
+
+        int size[] = simPhoneBook.getAdnRecordsSize(SimConstants.EF_ADN);
+        assertNotNull(size);
+        assertEquals(3, size.length);
+        assertEquals(size[0] * size[2], size[1]);
+        assertTrue(size[2] >= 100);
+
+        List<AdnRecord> adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+        // do it twice cause the second time shall read from cache only
+        adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+        assertNotNull(adnRecordList);
+
+        // Test for phone book update
+        int adnIndex, listIndex = 0;
+        AdnRecord originalAdn = null;
+        // We need to maintain the state of the SIM before and after the test.
+        // Since this test doesn't mock the SIM we try to get a valid ADN record,
+        // for 3 tries and if this fails, we bail out.
+        for (adnIndex = 3 ; adnIndex >= 1; adnIndex--) {
+            listIndex = adnIndex - 1; // listIndex is zero based.
+            originalAdn = adnRecordList.get(listIndex);
+            assertNotNull("Original Adn is Null.", originalAdn);
+            assertNotNull("Original Adn alpha tag is null.", originalAdn.getAlphaTag());
+            assertNotNull("Original Adn number is null.", originalAdn.getNumber());
+
+            if (originalAdn.getNumber().length() > 0 &&
+                originalAdn.getAlphaTag().length() > 0) {
+                break;
+            }
+        }
+        if (adnIndex == 0) return;
+
+        AdnRecord emptyAdn = new AdnRecord("", "");
+        AdnRecord firstAdn = new AdnRecord("John", "4085550101");
+        AdnRecord secondAdn = new AdnRecord("Andy", "6505550102");
+        String pin2 = null;
+
+        // udpate by index
+        boolean success = simPhoneBook.updateAdnRecordsInEfByIndex(SimConstants.EF_ADN,
+                firstAdn.getAlphaTag(), firstAdn.getNumber(), adnIndex, pin2);
+        adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+         AdnRecord tmpAdn = adnRecordList.get(listIndex);
+        assertTrue(success);
+        assertTrue(firstAdn.isEqual(tmpAdn));
+
+        // replace by search
+        success = simPhoneBook.updateAdnRecordsInEfBySearch(SimConstants.EF_ADN,
+                firstAdn.getAlphaTag(), firstAdn.getNumber(),
+                secondAdn.getAlphaTag(), secondAdn.getNumber(), pin2);
+        adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+        tmpAdn = adnRecordList.get(listIndex);
+        assertTrue(success);
+        assertFalse(firstAdn.isEqual(tmpAdn));
+        assertTrue(secondAdn.isEqual(tmpAdn));
+
+        // erase be search
+        success = simPhoneBook.updateAdnRecordsInEfBySearch(SimConstants.EF_ADN,
+                secondAdn.getAlphaTag(), secondAdn.getNumber(),
+                emptyAdn.getAlphaTag(), emptyAdn.getNumber(), pin2);
+        adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+        tmpAdn = adnRecordList.get(listIndex);
+        assertTrue(success);
+        assertTrue(tmpAdn.isEmpty());
+
+        // restore the orginial adn
+        success = simPhoneBook.updateAdnRecordsInEfByIndex(SimConstants.EF_ADN,
+                originalAdn.getAlphaTag(), originalAdn.getNumber(), adnIndex,
+                pin2);
+        adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+        tmpAdn = adnRecordList.get(listIndex);
+        assertTrue(success);
+        assertTrue(originalAdn.isEqual(tmpAdn));
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java
new file mode 100644
index 0000000..6ced23d
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.os.ServiceManager;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class SimSmsTest extends TestCase {
+
+    @MediumTest
+    @Suppress // TODO: suppress this test for now since it doesn't work on the emulator
+    public void testBasic() throws Exception {
+
+        ISms sms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+        assertNotNull(sms);
+
+        List<SmsRawData> records = sms.getAllMessagesFromSimEf();
+        assertNotNull(records);
+        assertTrue(records.size() >= 0);
+
+        int firstNullIndex = -1;
+        int firstValidIndex = -1;
+        byte[] pdu = null;
+        for (int i = 0; i < records.size(); i++) {
+            SmsRawData data = records.get(i);
+            if (data != null && firstValidIndex == -1) {
+                firstValidIndex = i;
+                pdu = data.getBytes();
+            }
+            if (data == null && firstNullIndex == -1) {
+                firstNullIndex = i;
+            }
+            if (firstNullIndex != -1 && firstValidIndex != -1) {
+                break;
+            }
+        }
+        if (firstNullIndex == -1 || firstValidIndex == -1)
+            return;
+        assertNotNull(pdu);
+    }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java
new file mode 100644
index 0000000..3fbc8f5
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import com.android.internal.telephony.gsm.SimTlv;
+import com.android.internal.telephony.gsm.SimUtils;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+
+public class SimUtilsTest extends TestCase {
+
+    @SmallTest
+    public void testBasic() throws Exception {
+        byte[] data, data2;
+
+        /* 
+         * bcdToString()
+         */
+
+        // An EF[ICCID] record
+        data = SimUtils.hexStringToBytes("981062400510444868f2");
+        assertEquals("8901260450014484862", SimUtils.bcdToString(data, 0, data.length));
+
+        // skip the first and last bytes
+        assertEquals("0126045001448486", SimUtils.bcdToString(data, 1, data.length - 2));
+
+        // Stops on invalid BCD value
+        data = SimUtils.hexStringToBytes("98F062400510444868f2");
+        assertEquals("890", SimUtils.bcdToString(data, 0, data.length));
+
+        /*
+        * bcdByteToInt()
+        */
+
+        assertEquals(98, SimUtils.bcdByteToInt((byte) 0x89));
+
+        // Out of range is treated as 0
+        assertEquals(8, SimUtils.bcdByteToInt((byte) 0x8c));
+
+        /*
+         * adnStringFieldToString()
+         */
+
+
+        data = SimUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff");
+        // Again, skip prepended 0
+        // (this is an EF[ADN] record)
+        assertEquals("Voice Mail", SimUtils.adnStringFieldToString(data, 1, data.length - 15));
+
+        data = SimUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF");
+        // (this is from an EF[ADN] record)
+        assertEquals("\u9673\u539A\u5764/M", SimUtils.adnStringFieldToString(data, 0, data.length));
+
+        data = SimUtils.hexStringToBytes("810A01566fec6365204de0696cFFFFFF");
+        // (this is made up to test since I don't have a real one)
+        assertEquals("Vo\u00ECce M\u00E0il", SimUtils.adnStringFieldToString(data, 0, data.length));
+
+        data = SimUtils.hexStringToBytes("820505302D82d32d31");
+        // Example from 3GPP TS 11.11 V18.1.3.0 annex B
+        assertEquals("-\u0532\u0583-1", SimUtils.adnStringFieldToString(data, 0, data.length));
+    }
+
+}
+
diff --git a/tests/CoreTests/com/android/internal/util/PredicatesTest.java b/tests/CoreTests/com/android/internal/util/PredicatesTest.java
new file mode 100644
index 0000000..c46ff05
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/util/PredicatesTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 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.internal.util;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class PredicatesTest extends TestCase {
+
+    private static final Predicate<Object> TRUE = new Predicate<Object>() {
+        public boolean apply(Object o) {
+            return true;
+        }
+    };
+
+    private static final Predicate<Object> FALSE = new Predicate<Object>() {
+        public boolean apply(Object o) {
+            return false;
+        }
+    };
+
+    public void testAndPredicate_AllConditionsTrue() throws Exception {
+        assertTrue(Predicates.and(newArrayList(TRUE)).apply(null));
+        assertTrue(Predicates.and(newArrayList(TRUE, TRUE)).apply(null));
+    }
+
+    public void testAndPredicate_AtLeastOneConditionIsFalse() throws Exception {
+        assertFalse(Predicates.and(newArrayList(FALSE, TRUE, TRUE)).apply(null));
+        assertFalse(Predicates.and(newArrayList(TRUE, FALSE, TRUE)).apply(null));
+        assertFalse(Predicates.and(newArrayList(TRUE, TRUE, FALSE)).apply(null));
+    }
+
+    public void testOrPredicate_AllConditionsTrue() throws Exception {
+        assertTrue(Predicates.or(newArrayList(TRUE, TRUE, TRUE)).apply(null));
+    }
+
+    public void testOrPredicate_AllConditionsFalse() throws Exception {
+        assertFalse(Predicates.or(newArrayList(FALSE, FALSE, FALSE)).apply(null));
+    }
+
+    public void testOrPredicate_AtLeastOneConditionIsTrue() throws Exception {
+        assertTrue(Predicates.or(newArrayList(TRUE, FALSE, FALSE)).apply(null));
+        assertTrue(Predicates.or(newArrayList(FALSE, TRUE, FALSE)).apply(null));
+        assertTrue(Predicates.or(newArrayList(FALSE, FALSE, TRUE)).apply(null));
+    }
+
+    public void testNotPredicate() throws Exception {
+        assertTrue(Predicates.not(FALSE).apply(null));
+        assertFalse(Predicates.not(TRUE).apply(null));
+    }
+
+    private static <E> ArrayList<E> newArrayList(E... elements) {
+        ArrayList<E> list = new ArrayList<E>();
+        Collections.addAll(list, elements);
+        return list;
+    }
+
+}
diff --git a/tests/CoreTests/run_core_test.sh b/tests/CoreTests/run_core_test.sh
new file mode 100755
index 0000000..ffa31ed
--- /dev/null
+++ b/tests/CoreTests/run_core_test.sh
@@ -0,0 +1,6 @@
+framework=/system/framework
+bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
+adb shell exec dalvikvm -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=3001 \
+      -Xbootclasspath:$bpath -cp /data/app/android.core.apk \
+      -Djava.io.tmpdir=/sdcard/tmp \
+      com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/CoreTests/run_junit.sh b/tests/CoreTests/run_junit.sh
new file mode 100755
index 0000000..b77794d
--- /dev/null
+++ b/tests/CoreTests/run_junit.sh
@@ -0,0 +1,9 @@
+# runs unit tests over adb shell using dalvikvm.  The value added is setting the classpath for you
+# and pointing to the junit textui test runner.
+#
+# the normal usage might be:
+# (make MoreJavaTests)
+# $ adb sync
+# $ java/tests/run_junit.sh android.util.MyTest
+
+adb shell exec dalvikvm -cp system/app/MoreTests.apk junit.textui.TestRunner $*
diff --git a/tests/DpiTest/Android.mk b/tests/DpiTest/Android.mk
new file mode 100644
index 0000000..3596c39
--- /dev/null
+++ b/tests/DpiTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := DensityTest
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DpiTest/AndroidManifest.xml b/tests/DpiTest/AndroidManifest.xml
new file mode 100644
index 0000000..f71cff2
--- /dev/null
+++ b/tests/DpiTest/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.google.android.test.dpi">
+    <application android:label="DpiTest">
+        <activity android:name="DpiTestActivity" android:label="DpiTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/DpiTest/res/drawable-120dpi/logo120dpi.png b/tests/DpiTest/res/drawable-120dpi/logo120dpi.png
new file mode 100644
index 0000000..46bbd5b
--- /dev/null
+++ b/tests/DpiTest/res/drawable-120dpi/logo120dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-240dpi/logo240dpi.png b/tests/DpiTest/res/drawable-240dpi/logo240dpi.png
new file mode 100644
index 0000000..4d717a8
--- /dev/null
+++ b/tests/DpiTest/res/drawable-240dpi/logo240dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable/logo160dpi.png b/tests/DpiTest/res/drawable/logo160dpi.png
new file mode 100644
index 0000000..c23b2ce
--- /dev/null
+++ b/tests/DpiTest/res/drawable/logo160dpi.png
Binary files differ
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
new file mode 100644
index 0000000..3759622
--- /dev/null
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2008 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.google.android.test.dpi;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.ScrollView;
+import android.view.View;
+import android.content.Context;
+
+public class DpiTestActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout root = new LinearLayout(this);
+        root.setOrientation(LinearLayout.VERTICAL);
+
+        LinearLayout layout = new LinearLayout(this);
+        addBitmapDrawable(layout, R.drawable.logo120dpi, true);
+        addBitmapDrawable(layout, R.drawable.logo160dpi, true);
+        addBitmapDrawable(layout, R.drawable.logo240dpi, true);
+        addLabelToRoot(root, "Prescaled bitmap in drawable");
+        addChildToRoot(root, layout);
+
+        layout = new LinearLayout(this);
+        addBitmapDrawable(layout, R.drawable.logo120dpi, false);
+        addBitmapDrawable(layout, R.drawable.logo160dpi, false);
+        addBitmapDrawable(layout, R.drawable.logo240dpi, false);
+        addLabelToRoot(root, "Autoscaled bitmap in drawable");
+        addChildToRoot(root, layout);
+
+        layout = new LinearLayout(this);
+        addResourceDrawable(layout, R.drawable.logo120dpi);
+        addResourceDrawable(layout, R.drawable.logo160dpi);
+        addResourceDrawable(layout, R.drawable.logo240dpi);
+        addLabelToRoot(root, "Prescaled resource drawable");
+        addChildToRoot(root, layout);
+
+        layout = new LinearLayout(this);
+        addCanvasBitmap(layout, R.drawable.logo120dpi, true);
+        addCanvasBitmap(layout, R.drawable.logo160dpi, true);
+        addCanvasBitmap(layout, R.drawable.logo240dpi, true);
+        addLabelToRoot(root, "Prescaled bitmap");
+        addChildToRoot(root, layout);
+
+        layout = new LinearLayout(this);
+        addCanvasBitmap(layout, R.drawable.logo120dpi, false);
+        addCanvasBitmap(layout, R.drawable.logo160dpi, false);
+        addCanvasBitmap(layout, R.drawable.logo240dpi, false);
+        addLabelToRoot(root, "Autoscaled bitmap");
+        addChildToRoot(root, layout);
+
+        setContentView(scrollWrap(root));
+    }
+
+    private View scrollWrap(View view) {
+        ScrollView scroller = new ScrollView(this);
+        scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.FILL_PARENT,
+                ScrollView.LayoutParams.FILL_PARENT));
+        return scroller;
+    }
+
+    private void addLabelToRoot(LinearLayout root, String text) {
+        TextView label = new TextView(this);
+        label.setText(text);
+        root.addView(label, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT));
+    }
+
+    private void addChildToRoot(LinearLayout root, LinearLayout layout) {
+        root.addView(layout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT));
+    }
+
+    private void addBitmapDrawable(LinearLayout layout, int resource, boolean scale) {
+        Bitmap bitmap;
+        bitmap = loadAndPrintDpi(resource, scale);
+
+        View view = new View(this);
+
+        final BitmapDrawable d = new BitmapDrawable(bitmap);
+        if (!scale) d.setDensityScale(getResources().getDisplayMetrics());
+        view.setBackgroundDrawable(d);
+
+        view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(),
+                d.getIntrinsicHeight()));
+        layout.addView(view);
+    }
+
+    private void addResourceDrawable(LinearLayout layout, int resource) {
+        View view = new View(this);
+
+        final Drawable d = getResources().getDrawable(resource);
+        view.setBackgroundDrawable(d);
+
+        view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(),
+                d.getIntrinsicHeight()));
+        layout.addView(view);
+    }
+
+    private void addCanvasBitmap(LinearLayout layout, int resource, boolean scale) {
+        Bitmap bitmap;
+        bitmap = loadAndPrintDpi(resource, scale);
+
+        ScaledBitmapView view = new ScaledBitmapView(this, bitmap);
+
+        view.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT));
+        layout.addView(view);
+    }
+
+    private Bitmap loadAndPrintDpi(int id, boolean scale) {
+        Bitmap bitmap;
+        if (scale) {
+            bitmap = BitmapFactory.decodeResource(getResources(), id);
+        } else {
+            BitmapFactory.Options opts = new BitmapFactory.Options();
+            opts.inScaled = false;
+            bitmap = BitmapFactory.decodeResource(getResources(), id, opts);
+        }
+        return bitmap;
+    }
+
+    private class ScaledBitmapView extends View {
+        private Bitmap mBitmap;
+
+        public ScaledBitmapView(Context context, Bitmap bitmap) {
+            super(context);
+            mBitmap = bitmap;
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            setMeasuredDimension(mBitmap.getScaledWidth(), mBitmap.getScaledHeight());
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
+        }
+    }
+}
diff --git a/tests/DumpRenderTree/Android.mk b/tests/DumpRenderTree/Android.mk
new file mode 100644
index 0000000..505a436
--- /dev/null
+++ b/tests/DumpRenderTree/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := DumpRenderTree
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
new file mode 100644
index 0000000..8e06cc8
--- /dev/null
+++ b/tests/DumpRenderTree/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.dumprendertree">
+    <application android:name="HTMLHostApp">
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="Menu" android:label="1 Dump Render Tree">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+        <activity android:name="HTMLHostActivity">
+        </activity>
+    </application>
+
+    <instrumentation android:name=".LayoutTestsAutoRunner"
+        android:targetPackage="com.android.dumprendertree"
+        android:label="Layout test automation runner"
+    />
+</manifest>
diff --git a/tests/DumpRenderTree/compare_layout_results.py b/tests/DumpRenderTree/compare_layout_results.py
new file mode 100644
index 0000000..c4285f1
--- /dev/null
+++ b/tests/DumpRenderTree/compare_layout_results.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+"""
+Compares results of two webkit layout test runs and writes
+results to a file.
+"""
+
+import optparse
+import os
+import sys
+
+def DiffResults(marker, new_results, old_results, diff_results, strip_reason):
+   """ Given two result files, generate diff and
+       write to diff_results file. All arguments are absolute paths
+       to files.
+   """
+   old_file = open(old_results, "r")
+   new_file = open(new_results, "r")
+   diff_file = open(diff_results, "a") 
+
+   # Read lines from each file
+   ndict = new_file.readlines()
+   cdict = old_file.readlines()
+
+   # Write marker to diff file
+   diff_file.writelines(marker + "\n")
+   diff_file.writelines("###############\n")
+
+   # Strip reason from result lines
+   if strip_reason is True:
+     for i in range(0, len(ndict)):
+       ndict[i] = ndict[i].split(' ')[0] + "\n"
+     for i in range(0, len(cdict)):
+       cdict[i] = cdict[i].split(' ')[0] + "\n"
+
+   # Find results in new_results missing in old_results
+   new_count=0
+   for line in ndict:
+     if line not in cdict:
+       diff_file.writelines("+ " + line)
+       new_count += 1
+
+   # Find results in old_results missing in new_results
+   missing_count=0
+   for line in cdict:
+     if line not in ndict:
+       diff_file.writelines("- " + line)
+       missing_count += 1
+
+   print marker + "  >>> added " + str(new_count) + " tests, removed " + str(missing_count) + " tests" 
+
+   diff_file.writelines("\n\n")
+
+   old_file.close()
+   new_file.close()
+   diff_file.close()
+   return
+
+def main(options, args):
+  results_dir = os.path.abspath(options.results_directory)
+  ref_dir = options.ref_directory
+
+  # if ref_dir is null, cannonify ref_dir to the script dir.
+  if not ref_dir:
+    script_self = sys.argv[0]
+    script_dir = os.path.dirname(script_self)
+    ref_dir = os.path.join(script_dir, "results")
+
+  ref_dir = os.path.abspath(ref_dir)
+
+  diff_result = os.path.join(results_dir, "layout_tests_diff.txt") 
+  if os.path.exists(diff_result):
+    os.remove(diff_result)
+
+  files=["passed", "failed", "nontext", "crashed"]
+  for f in files:
+    result_file_name = "layout_tests_" + f + ".txt"
+    DiffResults(f, os.path.join(results_dir, result_file_name),
+                os.path.join(ref_dir, result_file_name), diff_result,
+                f == "failed")
+
+if '__main__' == __name__:
+  option_parser = optparse.OptionParser()
+  option_parser.add_option("", "--ref-directory",
+                           default=None,
+                           dest="ref_directory",
+                           help="directory name under which results are stored.")
+
+  option_parser.add_option("", "--results-directory",
+                           default="layout-test-results/",
+                           dest="results_directory",
+                           help="directory name under which results are stored.")
+  options, args = option_parser.parse_args()
+  main(options, args)
diff --git a/tests/DumpRenderTree/results/layout_tests_crashed.txt b/tests/DumpRenderTree/results/layout_tests_crashed.txt
new file mode 100644
index 0000000..1859f07
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_crashed.txt
@@ -0,0 +1,2 @@
+/sdcard/android/layout_tests/fast/js/regexp-charclass-crash.html
+/sdcard/android/layout_tests/fast/canvas/gradient-add-second-start-end-stop.html
diff --git a/tests/DumpRenderTree/results/layout_tests_failed.txt b/tests/DumpRenderTree/results/layout_tests_failed.txt
new file mode 100644
index 0000000..5a20b52
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_failed.txt
@@ -0,0 +1,283 @@
+/sdcard/android/layout_tests/fast/text/zero-width-characters.html :  different length
+/sdcard/android/layout_tests/fast/text/reset-drag-on-mouse-down.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/text/plain-text-line-breaks.html :  different length
+/sdcard/android/layout_tests/fast/replaced/table-percent-height.html :  different length
+/sdcard/android/layout_tests/fast/replaced/image-map.html :  different length
+/sdcard/android/layout_tests/fast/replaced/image-map-bug16782.html :  different length
+/sdcard/android/layout_tests/fast/parser/xml-declaration-missing-ending-mark.html :  different length
+/sdcard/android/layout_tests/fast/parser/tabindex-parsing.html :  different length
+/sdcard/android/layout_tests/fast/parser/script-tag-with-trailing-slash.html :  different length
+/sdcard/android/layout_tests/fast/parser/external-entities.xml :  different length
+/sdcard/android/layout_tests/fast/parser/entity-end-script-tag.html :  different length
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-iframe.html :   @offset: 0
+/sdcard/android/layout_tests/fast/parser/comment-in-iframe.html :   @offset: 0
+/sdcard/android/layout_tests/fast/overflow/scroll-vertical-not-horizontal.html :  different length
+/sdcard/android/layout_tests/fast/loader/xmlhttprequest-missing-file-exception.html :  different length
+/sdcard/android/layout_tests/fast/loader/stop-provisional-loads.html :  different length
+/sdcard/android/layout_tests/fast/loader/plain-text-document.html :  different length
+/sdcard/android/layout_tests/fast/loader/opaque-base-url.html :   @offset: 129
+/sdcard/android/layout_tests/fast/loader/onunload-form-submit-crash.html :  different length
+/sdcard/android/layout_tests/fast/loader/onunload-form-submit-crash-2.html :  different length
+/sdcard/android/layout_tests/fast/loader/local-JavaScript-from-local.html :  different length
+/sdcard/android/layout_tests/fast/loader/local-image-from-local.html :  different length
+/sdcard/android/layout_tests/fast/loader/local-iFrame-source-from-local.html :  different length
+/sdcard/android/layout_tests/fast/loader/local-CSS-from-local.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/loader/data-url-encoding-svg.html :  different length
+/sdcard/android/layout_tests/fast/loader/cancel-load-during-port-block-timer.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/var-shadows-arg-gc-crash.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/try-catch-crash.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/toString-and-valueOf-override.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/recursion-limit-equal.html :  different length
+/sdcard/android/layout_tests/fast/js/navigator-mimeTypes-length.html :  different length
+/sdcard/android/layout_tests/fast/js/math-transforms.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/global-recursion-on-full-stack.html :  different length
+/sdcard/android/layout_tests/fast/js/global-constructors.html :  different length
+/sdcard/android/layout_tests/fast/js/exceptions-thrown-in-callbacks.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-sequencing.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-sequencing-binops2.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-sequencing-binops.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-codegen-crash.html :  different length
+/sdcard/android/layout_tests/fast/js/duplicate-param-gc-crash.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/html/tab-order.html :   @offset: 246
+/sdcard/android/layout_tests/fast/history/subframe-is-visited.html :  different length
+/sdcard/android/layout_tests/fast/history/go-back-to-changed-name.html :  different length
+/sdcard/android/layout_tests/fast/frames/viewsource-empty-attribute-value.html :  different length
+/sdcard/android/layout_tests/fast/frames/removal-before-attach-crash.html :  different length
+/sdcard/android/layout_tests/fast/frames/iframe-window-focus.html :  different length
+/sdcard/android/layout_tests/fast/frames/frameElement-widthheight.html :  different length
+/sdcard/android/layout_tests/fast/frames/frame-js-url-clientWidth.html :  different length
+/sdcard/android/layout_tests/fast/frames/frame-base-url.html :  different length
+/sdcard/android/layout_tests/fast/frames/empty-frame-src.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/mailto/post-text-plain.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-text-plain-with-accept-charset.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-x-www-form-urlencoded.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-text-plain.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-multipart-form-data.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-append-query.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-overwrite-query.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-text-plain.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-text-plain-latin-1.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-always-utf-8.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items-x-www-form-urlencoded.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items-text-plain.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/advanced-put.html :  different length
+/sdcard/android/layout_tests/fast/forms/mailto/advanced-get.html :  different length
+/sdcard/android/layout_tests/fast/forms/textfield-to-password-on-focus.html :  different length
+/sdcard/android/layout_tests/fast/forms/textfield-onchange-deletion.html :  different length
+/sdcard/android/layout_tests/fast/forms/textfield-inside-anchor.html :  different length
+/sdcard/android/layout_tests/fast/forms/textarea-type-spaces.html :  different length
+/sdcard/android/layout_tests/fast/forms/textarea-scrolled-endline-caret.html :  different length
+/sdcard/android/layout_tests/fast/forms/textarea-paste-newline.html :  different length
+/sdcard/android/layout_tests/fast/forms/textarea-no-scroll-on-blur.html :   @offset: 79
+/sdcard/android/layout_tests/fast/forms/textarea-initial-caret-position.html :  different length
+/sdcard/android/layout_tests/fast/forms/textarea-hard-linewrap.html :  different length
+/sdcard/android/layout_tests/fast/forms/textarea-default-value-leading-newline.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/textarea-appearance-wrap.html :  different length
+/sdcard/android/layout_tests/fast/forms/text-field-setvalue-crash.html :  different length
+/sdcard/android/layout_tests/fast/forms/stuff-on-my-optgroup.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/slider-onchange-event.html :  different length
+/sdcard/android/layout_tests/fast/forms/slider-mouse-events.html :  different length
+/sdcard/android/layout_tests/fast/forms/selection-functions.html :   @offset: 306
+/sdcard/android/layout_tests/fast/forms/select-type-ahead-non-latin.html :  different length
+/sdcard/android/layout_tests/fast/forms/select-enter-key.html :  different length
+/sdcard/android/layout_tests/fast/forms/select-empty-list.html :  different length
+/sdcard/android/layout_tests/fast/forms/select-double-onchange.html :  different length
+/sdcard/android/layout_tests/fast/forms/select-accesskey.html :  different length
+/sdcard/android/layout_tests/fast/forms/search-hidden-cancel-button.html :  different length
+/sdcard/android/layout_tests/fast/forms/search-event-delay.html :  different length
+/sdcard/android/layout_tests/fast/forms/search-click-in-placeholder.html :   @offset: 1
+/sdcard/android/layout_tests/fast/forms/search-cancel-button-mouseup.html :  different length
+/sdcard/android/layout_tests/fast/forms/plaintext-mode-1.html :  different length
+/sdcard/android/layout_tests/fast/forms/password-doubleclick-selection.html :  different length
+/sdcard/android/layout_tests/fast/forms/onselect-textfield.html :  different length
+/sdcard/android/layout_tests/fast/forms/onselect-textarea.html :  different length
+/sdcard/android/layout_tests/fast/forms/onselect-selectall.html :  different length
+/sdcard/android/layout_tests/fast/forms/onchange-enter-submit.html :  different length
+/sdcard/android/layout_tests/fast/forms/listbox-typeahead-scroll.html :  different length
+/sdcard/android/layout_tests/fast/forms/listbox-selection.html :  different length
+/sdcard/android/layout_tests/fast/forms/listbox-select-all.html :  different length
+/sdcard/android/layout_tests/fast/forms/listbox-onchange.html :  different length
+/sdcard/android/layout_tests/fast/forms/legend-access-key.html :  different length
+/sdcard/android/layout_tests/fast/forms/input-select-on-click.html :  different length
+/sdcard/android/layout_tests/fast/forms/input-radio-checked-tab.html :   @offset: 115
+/sdcard/android/layout_tests/fast/forms/input-maxlength.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/input-implicit-length-limit.html :  different length
+/sdcard/android/layout_tests/fast/forms/input-first-letter.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/input-delete.html :  different length
+/sdcard/android/layout_tests/fast/forms/form-element-geometry.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/form-collection-lookup.html :  different length
+/sdcard/android/layout_tests/fast/forms/form-and-frame-interaction-retains-values.html :  different length
+/sdcard/android/layout_tests/fast/forms/focus2.html :  different length
+/sdcard/android/layout_tests/fast/forms/focus.html :  different length
+/sdcard/android/layout_tests/fast/forms/focus-selection-textarea.html :  different length
+/sdcard/android/layout_tests/fast/forms/focus-selection-input.html :  different length
+/sdcard/android/layout_tests/fast/forms/focus-control-to-page.html :  different length
+/sdcard/android/layout_tests/fast/forms/enter-clicks-buttons.html :  different length
+/sdcard/android/layout_tests/fast/forms/drag-out-of-textarea.html :  different length
+/sdcard/android/layout_tests/fast/forms/drag-into-textarea.html :  different length
+/sdcard/android/layout_tests/fast/forms/check-box-enter-key.html :  different length
+/sdcard/android/layout_tests/fast/forms/button-state-restore.html :  different length
+/sdcard/android/layout_tests/fast/forms/button-spacebar-click.html :  different length
+/sdcard/android/layout_tests/fast/forms/button-enter-click.html :  different length
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-003.html :   @offset: 51
+/sdcard/android/layout_tests/fast/forms/access-key.html :  different length
+/sdcard/android/layout_tests/fast/events/window-events-capture.html :  different length
+/sdcard/android/layout_tests/fast/events/window-events-bubble2.html :  different length
+/sdcard/android/layout_tests/fast/events/window-events-bubble.html :  different length
+/sdcard/android/layout_tests/fast/events/tabindex-focus-chain.html :   @offset: 0
+/sdcard/android/layout_tests/fast/events/scrollbar-double-click.html :  different length
+/sdcard/android/layout_tests/fast/events/scroll-to-anchor-in-overflow-hidden.html :  different length
+/sdcard/android/layout_tests/fast/events/scroll-event-does-not-bubble.html :  different length
+/sdcard/android/layout_tests/fast/events/related-target.html :  different length
+/sdcard/android/layout_tests/fast/events/option-tab.html :  different length
+/sdcard/android/layout_tests/fast/events/open-window-from-another-frame.html :  different length
+/sdcard/android/layout_tests/fast/events/onunload.html :  different length
+/sdcard/android/layout_tests/fast/events/onunload-window-property.html :  different length
+/sdcard/android/layout_tests/fast/events/onunload-not-on-body.html :  different length
+/sdcard/android/layout_tests/fast/events/onunload-clears-onbeforeunload.html :  different length
+/sdcard/android/layout_tests/fast/events/onsearch-enter.html :  different length
+/sdcard/android/layout_tests/fast/events/onload-webkit-before-webcore.html :   @offset: 105
+/sdcard/android/layout_tests/fast/events/ondragenter.html :  different length
+/sdcard/android/layout_tests/fast/events/onclick-list-marker.html :  different length
+/sdcard/android/layout_tests/fast/events/onchange-textfield.html :  different length
+/sdcard/android/layout_tests/fast/events/onchange-select-popup.html :  different length
+/sdcard/android/layout_tests/fast/events/onchange-searchfield.html :  different length
+/sdcard/android/layout_tests/fast/events/onchange-passwordfield.html :  different length
+/sdcard/android/layout_tests/fast/events/onchange-click-hang.html :  different length
+/sdcard/android/layout_tests/fast/events/mouseup-outside-document.html :  different length
+/sdcard/android/layout_tests/fast/events/mouseup-from-button2.html :  different length
+/sdcard/android/layout_tests/fast/events/mouseover-mouseout2.html :  different length
+/sdcard/android/layout_tests/fast/events/mouseover-mouseout.html :  different length
+/sdcard/android/layout_tests/fast/events/mouseout-on-window.html :  different length
+/sdcard/android/layout_tests/fast/events/mouseout-dead-subframe.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/mousemove-after-drag-over-scrollbar.html :  different length
+/sdcard/android/layout_tests/fast/events/mouseclick-target-and-positioning.html :  different length
+/sdcard/android/layout_tests/fast/events/mouse-click-events.html :  different length
+/sdcard/android/layout_tests/fast/events/keypress-insert-tab.html :   @offset: 85
+/sdcard/android/layout_tests/fast/events/keypress-focus-change.html :  different length
+/sdcard/android/layout_tests/fast/events/keydown-keypress-preventDefault.html :   @offset: 228
+/sdcard/android/layout_tests/fast/events/keydown-keypress-focus-change.html :   @offset: 172
+/sdcard/android/layout_tests/fast/events/key-events-in-input-text.html :  different length
+/sdcard/android/layout_tests/fast/events/key-events-in-input-button.html :  different length
+/sdcard/android/layout_tests/fast/events/js-keyboard-event-creation.html :  different length
+/sdcard/android/layout_tests/fast/events/input-image-scrolled-x-y.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/iframe-object-onload.html :  different length
+/sdcard/android/layout_tests/fast/events/frame-tab-focus.html :  different length
+/sdcard/android/layout_tests/fast/events/frame-programmatic-focus.html :  different length
+/sdcard/android/layout_tests/fast/events/frame-click-focus.html :  different length
+/sdcard/android/layout_tests/fast/events/fire-scroll-event.html :  different length
+/sdcard/android/layout_tests/fast/events/event-view-toString.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/drag-outside-window.html :   @offset: 20
+/sdcard/android/layout_tests/fast/events/drag-in-frames.html :  different length
+/sdcard/android/layout_tests/fast/events/dblclick-addEventListener.html :  different length
+/sdcard/android/layout_tests/fast/events/contextmenu-scrolled-page-with-frame.html :  different length
+/sdcard/android/layout_tests/fast/events/content-changed-during-drop.html :  different length
+/sdcard/android/layout_tests/fast/events/click-count.html :  different length
+/sdcard/android/layout_tests/fast/events/capture-on-target.html :  different length
+/sdcard/android/layout_tests/fast/events/autoscroll-with-non-scrollable-parent.html :  different length
+/sdcard/android/layout_tests/fast/events/autoscroll-nonscrollable-iframe-in-scrollable-div.html :  different length
+/sdcard/android/layout_tests/fast/events/autoscroll-in-textfield.html :  different length
+/sdcard/android/layout_tests/fast/events/arrow-navigation.html :  different length
+/sdcard/android/layout_tests/fast/events/arrow-keys-on-body.html :  different length
+/sdcard/android/layout_tests/fast/events/anchor-image-scrolled-x-y.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/access-key-self-destruct.html :  different length
+/sdcard/android/layout_tests/fast/encoding/xml-utf-8-default.xml :  different length
+/sdcard/android/layout_tests/fast/encoding/url-host-name-non-ascii.html :  different length
+/sdcard/android/layout_tests/fast/encoding/percent-escaping.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/encoding/mailto-always-utf-8.html :  different length
+/sdcard/android/layout_tests/fast/encoding/invalid-xml.html :  different length
+/sdcard/android/layout_tests/fast/encoding/idn-security.html :  different length
+/sdcard/android/layout_tests/fast/encoding/frame-default-enc.html :   @offset: 0
+/sdcard/android/layout_tests/fast/encoding/charset-koi8-u.html :   @offset: 147
+/sdcard/android/layout_tests/fast/encoding/char-encoding.html :  different length
+/sdcard/android/layout_tests/fast/encoding/char-decoding.html :  different length
+/sdcard/android/layout_tests/fast/dynamic/paused-event-dispatch.html :   @offset: 117
+/sdcard/android/layout_tests/fast/dom/Window/window-xy-properties.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/window-scroll-arguments.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/window-screen-properties.html :   @offset: 65
+/sdcard/android/layout_tests/fast/dom/Window/window-resize.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/window-resize-and-move-arguments.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/window-property-clearing.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/window-properties.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/window-open-pending-url.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/window-onFocus.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/window-function-name-getter-precedence.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/window-early-properties.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/setting-properties-on-closed-window.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/redirect-with-timer.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/Plug-ins.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/orphaned-frame-access.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/new-window-opener.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/get-set-properties.html :   @offset: 0
+/sdcard/android/layout_tests/fast/dom/Window/dom-access-from-closure-window.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/dom-access-from-closure-iframe.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/console-functions.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/closure-access-after-navigation-window.html :  different length
+/sdcard/android/layout_tests/fast/dom/Window/clear-timeout.html :  different length
+/sdcard/android/layout_tests/fast/dom/StyleSheet/ownerNode-lifetime-2.html :  different length
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/listbox-select-reset.html :  different length
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/object-as-frame.html :  different length
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/hasFocus.html :  different length
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/activeElement.html :  different length
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/011.xml :  different length
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/010.xml :  different length
+/sdcard/android/layout_tests/fast/dom/Element/offsetLeft-offsetTop-body-quirk.html :  different length
+/sdcard/android/layout_tests/fast/dom/DOMException/XPathException.html :  different length
+/sdcard/android/layout_tests/fast/dom/wrapper-classes.html :  different length
+/sdcard/android/layout_tests/fast/dom/tabindex-clamp.html :  different length
+/sdcard/android/layout_tests/fast/dom/simultaneouslyRegsiteredTimerFireOrder.html :  different length
+/sdcard/android/layout_tests/fast/dom/set-frame-src-while-running-script-in-frame.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex.html :  different length
+/sdcard/android/layout_tests/fast/dom/open-and-close-by-DOM.html :  different length
+/sdcard/android/layout_tests/fast/dom/onerror-img.html :  different length
+/sdcard/android/layout_tests/fast/dom/object-plugin-hides-properties.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/object-embed-plugin-scripting.html :  different length
+/sdcard/android/layout_tests/fast/dom/null-document-window-open-crash.html :  different length
+/sdcard/android/layout_tests/fast/dom/null-document-location-replace-crash.html :  different length
+/sdcard/android/layout_tests/fast/dom/null-document-location-put-crash.html :  different length
+/sdcard/android/layout_tests/fast/dom/null-document-location-href-put-crash.html :  different length
+/sdcard/android/layout_tests/fast/dom/null-document-location-assign-crash.html :  different length
+/sdcard/android/layout_tests/fast/dom/null-chardata-crash.html :  different length
+/sdcard/android/layout_tests/fast/dom/noscript-style.html :  different length
+/sdcard/android/layout_tests/fast/dom/noscript-canvas-in-created-html-document.html :  different length
+/sdcard/android/layout_tests/fast/dom/non-numeric-values-numeric-parameters.html :  different length
+/sdcard/android/layout_tests/fast/dom/node-item.html :  different length
+/sdcard/android/layout_tests/fast/dom/node-filter-gc.html :   @offset: 1
+/sdcard/android/layout_tests/fast/dom/no-elements.html :  different length
+/sdcard/android/layout_tests/fast/dom/navigator-vendorSub.html :  different length
+/sdcard/android/layout_tests/fast/dom/namespaces-1.html :  different length
+/sdcard/android/layout_tests/fast/dom/NamedNodeMap-setNamedItem-crash.html :  different length
+/sdcard/android/layout_tests/fast/dom/namednodemap-namelookup.html :  different length
+/sdcard/android/layout_tests/fast/dom/mutation-event-remove-inserted-node.html :  different length
+/sdcard/android/layout_tests/fast/dom/location-hash.html :  different length
+/sdcard/android/layout_tests/fast/dom/length-attribute-mapping.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/javascript-url-crash-function.html :  different length
+/sdcard/android/layout_tests/fast/dom/inner-text-001.html :  different length
+/sdcard/android/layout_tests/fast/dom/global-constructors.html :  different length
+/sdcard/android/layout_tests/fast/dom/gc-acid3.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/gc-9.html :  different length
+/sdcard/android/layout_tests/fast/dom/gc-8.html :  different length
+/sdcard/android/layout_tests/fast/dom/frame-loading-via-document-write.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/documenturi-not-affected-by-base-tag.html :  different length
+/sdcard/android/layout_tests/fast/dom/documenturi-can-hold-arbitrary-string.html :  different length
+/sdcard/android/layout_tests/fast/dom/document-width-height-force-layout.html :   @offset: 142
+/sdcard/android/layout_tests/fast/dom/constructors-cached.html :  different length
+/sdcard/android/layout_tests/fast/dom/constructors-cached-navigate.html :  different length
+/sdcard/android/layout_tests/fast/dom/client-width-height.html :   @offset: 119
+/sdcard/android/layout_tests/fast/dom/client-width-height-quirks.html :   @offset: 115
+/sdcard/android/layout_tests/fast/dom/assign-to-window-status.html :  different length
+/sdcard/android/layout_tests/fast/css/variables/color-hex-test.html :  different length
+/sdcard/android/layout_tests/fast/css/html-attr-case-sensitivity.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/css/hover-affects-child.html :  different length
+/sdcard/android/layout_tests/fast/css/getComputedStyle-transform.html :  different length
+/sdcard/android/layout_tests/fast/css/dashboard-region-parser.html :  different length
+/sdcard/android/layout_tests/fast/css/computed-style.html :  different length
+/sdcard/android/layout_tests/fast/css/computed-style-without-renderer.html :  different length
+/sdcard/android/layout_tests/fast/canvas/toDataURL-supportedTypes.html :  different length
+/sdcard/android/layout_tests/fast/canvas/canvas-save-restore-with-path.html :  different length
+/sdcard/android/layout_tests/fast/canvas/canvas-longlived-context.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/canvas/canvas-getImageData.html :  different length
+/sdcard/android/layout_tests/fast/canvas/canvas-alphaImageData-behavior.html :  different length
diff --git a/tests/DumpRenderTree/results/layout_tests_nontext.txt b/tests/DumpRenderTree/results/layout_tests_nontext.txt
new file mode 100644
index 0000000..0355cb72
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_nontext.txt
@@ -0,0 +1,1658 @@
+/sdcard/android/layout_tests/fast/transforms/transforms-with-opacity.html
+/sdcard/android/layout_tests/fast/transforms/transform-positioned-ancestor.html
+/sdcard/android/layout_tests/fast/transforms/transform-overflow.html
+/sdcard/android/layout_tests/fast/transforms/skew-with-unitless-zero.html
+/sdcard/android/layout_tests/fast/transforms/shadows.html
+/sdcard/android/layout_tests/fast/transforms/overflow-with-transform.html
+/sdcard/android/layout_tests/fast/transforms/matrix-02.html
+/sdcard/android/layout_tests/fast/transforms/matrix-01.html
+/sdcard/android/layout_tests/fast/transforms/identity-matrix.html
+/sdcard/android/layout_tests/fast/transforms/diamond.html
+/sdcard/android/layout_tests/fast/tokenizer/script_extra_close.html
+/sdcard/android/layout_tests/fast/tokenizer/script-after-frameset.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-title-end-tag-2.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-title-end-tag-1.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-style-end-tag-2.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-style-end-tag-1.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-write_2.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-write.html
+/sdcard/android/layout_tests/fast/tokenizer/003.html
+/sdcard/android/layout_tests/fast/tokenizer/002.html
+/sdcard/android/layout_tests/fast/tokenizer/001.html
+/sdcard/android/layout_tests/fast/text/whitespace/tab-character-basics.html
+/sdcard/android/layout_tests/fast/text/whitespace/span-in-word-space-causes-overflow.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-spaces-after-newline.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-overflow-selection.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-line-test.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-last-char.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-newline-box-test.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-break-word.html
+/sdcard/android/layout_tests/fast/text/whitespace/nowrap-clear-float.html
+/sdcard/android/layout_tests/fast/text/whitespace/normal-after-nowrap-breaking.html
+/sdcard/android/layout_tests/fast/text/whitespace/nbsp-mode-and-linewraps.html
+/sdcard/android/layout_tests/fast/text/whitespace/030.html
+/sdcard/android/layout_tests/fast/text/whitespace/029.html
+/sdcard/android/layout_tests/fast/text/whitespace/028.html
+/sdcard/android/layout_tests/fast/text/whitespace/027.html
+/sdcard/android/layout_tests/fast/text/whitespace/026.html
+/sdcard/android/layout_tests/fast/text/whitespace/025.html
+/sdcard/android/layout_tests/fast/text/whitespace/024.html
+/sdcard/android/layout_tests/fast/text/whitespace/023.html
+/sdcard/android/layout_tests/fast/text/whitespace/022.html
+/sdcard/android/layout_tests/fast/text/whitespace/021.html
+/sdcard/android/layout_tests/fast/text/whitespace/020.html
+/sdcard/android/layout_tests/fast/text/whitespace/019.html
+/sdcard/android/layout_tests/fast/text/whitespace/018.html
+/sdcard/android/layout_tests/fast/text/whitespace/017.html
+/sdcard/android/layout_tests/fast/text/whitespace/016.html
+/sdcard/android/layout_tests/fast/text/whitespace/015.html
+/sdcard/android/layout_tests/fast/text/whitespace/014.html
+/sdcard/android/layout_tests/fast/text/whitespace/013.html
+/sdcard/android/layout_tests/fast/text/whitespace/012.html
+/sdcard/android/layout_tests/fast/text/whitespace/011.html
+/sdcard/android/layout_tests/fast/text/whitespace/010.html
+/sdcard/android/layout_tests/fast/text/whitespace/009.html
+/sdcard/android/layout_tests/fast/text/whitespace/008.html
+/sdcard/android/layout_tests/fast/text/whitespace/007.html
+/sdcard/android/layout_tests/fast/text/whitespace/006.html
+/sdcard/android/layout_tests/fast/text/whitespace/005.html
+/sdcard/android/layout_tests/fast/text/whitespace/004.html
+/sdcard/android/layout_tests/fast/text/whitespace/003.html
+/sdcard/android/layout_tests/fast/text/whitespace/002.html
+/sdcard/android/layout_tests/fast/text/whitespace/001.html
+/sdcard/android/layout_tests/fast/text/international/wrap-CJK-001.html
+/sdcard/android/layout_tests/fast/text/international/thai-line-breaks.html
+/sdcard/android/layout_tests/fast/text/international/rtl-white-space-pre-wrap.html
+/sdcard/android/layout_tests/fast/text/international/rtl-caret.html
+/sdcard/android/layout_tests/fast/text/international/hindi-spacing.html
+/sdcard/android/layout_tests/fast/text/international/complex-character-based-fallback.html
+/sdcard/android/layout_tests/fast/text/international/bidi-override.html
+/sdcard/android/layout_tests/fast/text/international/bidi-neutral-run.html
+/sdcard/android/layout_tests/fast/text/international/bidi-neutral-directionality-paragraph-start.html
+/sdcard/android/layout_tests/fast/text/international/bidi-menulist.html
+/sdcard/android/layout_tests/fast/text/international/bidi-listbox.html
+/sdcard/android/layout_tests/fast/text/international/bidi-listbox-atsui.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-HTML.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-formatting-characters.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-CSS.html
+/sdcard/android/layout_tests/fast/text/international/bidi-layout-across-linebreak.html
+/sdcard/android/layout_tests/fast/text/international/bidi-L2-run-reordering.html
+/sdcard/android/layout_tests/fast/text/international/bidi-innertext.html
+/sdcard/android/layout_tests/fast/text/international/bidi-ignored-for-first-child-inline.html
+/sdcard/android/layout_tests/fast/text/international/bidi-explicit-embedding.html
+/sdcard/android/layout_tests/fast/text/international/bidi-european-terminators.html
+/sdcard/android/layout_tests/fast/text/international/bidi-CS-after-AN.html
+/sdcard/android/layout_tests/fast/text/international/bidi-control-chars-treated-as-ZWS.html
+/sdcard/android/layout_tests/fast/text/international/bidi-AN-after-L.html
+/sdcard/android/layout_tests/fast/text/international/bidi-AN-after-empty-run.html
+/sdcard/android/layout_tests/fast/text/international/003.html
+/sdcard/android/layout_tests/fast/text/international/002.html
+/sdcard/android/layout_tests/fast/text/international/001.html
+/sdcard/android/layout_tests/fast/text/firstline/003.html
+/sdcard/android/layout_tests/fast/text/firstline/002.html
+/sdcard/android/layout_tests/fast/text/firstline/001.html
+/sdcard/android/layout_tests/fast/text/basic/generic-family-reset.html
+/sdcard/android/layout_tests/fast/text/basic/generic-family-changes.html
+/sdcard/android/layout_tests/fast/text/basic/015.html
+/sdcard/android/layout_tests/fast/text/basic/014.html
+/sdcard/android/layout_tests/fast/text/basic/013.html
+/sdcard/android/layout_tests/fast/text/basic/012.html
+/sdcard/android/layout_tests/fast/text/basic/011.html
+/sdcard/android/layout_tests/fast/text/basic/009.html
+/sdcard/android/layout_tests/fast/text/basic/008.html
+/sdcard/android/layout_tests/fast/text/basic/007.html
+/sdcard/android/layout_tests/fast/text/basic/006.html
+/sdcard/android/layout_tests/fast/text/basic/005.html
+/sdcard/android/layout_tests/fast/text/basic/004.html
+/sdcard/android/layout_tests/fast/text/basic/003.html
+/sdcard/android/layout_tests/fast/text/basic/002.html
+/sdcard/android/layout_tests/fast/text/basic/001.html
+/sdcard/android/layout_tests/fast/text/word-space.html
+/sdcard/android/layout_tests/fast/text/word-break.html
+/sdcard/android/layout_tests/fast/text/word-break-soft-hyphen.html
+/sdcard/android/layout_tests/fast/text/word-break-run-rounding.html
+/sdcard/android/layout_tests/fast/text/wide-zero-width-space.html
+/sdcard/android/layout_tests/fast/text/wbr.html
+/sdcard/android/layout_tests/fast/text/wbr-styled.html
+/sdcard/android/layout_tests/fast/text/wbr-pre.html
+/sdcard/android/layout_tests/fast/text/wbr-in-pre-crash.html
+/sdcard/android/layout_tests/fast/text/updateNewFont.html
+/sdcard/android/layout_tests/fast/text/trailing-white-space.html
+/sdcard/android/layout_tests/fast/text/trailing-white-space-2.html
+/sdcard/android/layout_tests/fast/text/textIteratorNilRenderer.html
+/sdcard/android/layout_tests/fast/text/stroking.html
+/sdcard/android/layout_tests/fast/text/stroking-decorations.html
+/sdcard/android/layout_tests/fast/text/stripNullFromText.html
+/sdcard/android/layout_tests/fast/text/softHyphen.html
+/sdcard/android/layout_tests/fast/text/soft-hyphen-3.html
+/sdcard/android/layout_tests/fast/text/soft-hyphen-2.html
+/sdcard/android/layout_tests/fast/text/should-use-atsui.html
+/sdcard/android/layout_tests/fast/text/shadow-no-blur.html
+/sdcard/android/layout_tests/fast/text/selection-painted-separately.html
+/sdcard/android/layout_tests/fast/text/selection-hard-linebreak.html
+/sdcard/android/layout_tests/fast/text/reset-emptyRun.html
+/sdcard/android/layout_tests/fast/text/monospace-width-cache.html
+/sdcard/android/layout_tests/fast/text/midword-break-hang.html
+/sdcard/android/layout_tests/fast/text/midword-break-after-breakable-char.html
+/sdcard/android/layout_tests/fast/text/line-breaks.html
+/sdcard/android/layout_tests/fast/text/line-breaks-after-white-space.html
+/sdcard/android/layout_tests/fast/text/letter-spacing-negative-opacity.html
+/sdcard/android/layout_tests/fast/text/large-text-composed-char.html
+/sdcard/android/layout_tests/fast/text/justified-selection.html
+/sdcard/android/layout_tests/fast/text/justified-selection-at-edge.html
+/sdcard/android/layout_tests/fast/text/in-rendered-text-rtl.html
+/sdcard/android/layout_tests/fast/text/font-initial.html
+/sdcard/android/layout_tests/fast/text/fixed-pitch-control-characters.html
+/sdcard/android/layout_tests/fast/text/embed-at-end-of-pre-wrap-line.html
+/sdcard/android/layout_tests/fast/text/drawBidiText.html
+/sdcard/android/layout_tests/fast/text/delete-hard-break-character.html
+/sdcard/android/layout_tests/fast/text/cg-vs-atsui.html
+/sdcard/android/layout_tests/fast/text/cg-fallback-bolding.html
+/sdcard/android/layout_tests/fast/text/capitalize-preserve-nbsp.html
+/sdcard/android/layout_tests/fast/text/capitalize-empty-generated-string.html
+/sdcard/android/layout_tests/fast/text/capitalize-boundaries.html
+/sdcard/android/layout_tests/fast/text/break-word.html
+/sdcard/android/layout_tests/fast/text/bidi-embedding-pop-and-push-same.html
+/sdcard/android/layout_tests/fast/text/atsui-spacing-features.html
+/sdcard/android/layout_tests/fast/text/atsui-small-caps-punctuation-size.html
+/sdcard/android/layout_tests/fast/text/atsui-rtl-override-selection.html
+/sdcard/android/layout_tests/fast/text/atsui-pointtooffset-calls-cg.html
+/sdcard/android/layout_tests/fast/text/atsui-partial-selection.html
+/sdcard/android/layout_tests/fast/text/atsui-multiple-renderers.html
+/sdcard/android/layout_tests/fast/text/atsui-kerning-and-ligatures.html
+/sdcard/android/layout_tests/fast/text/apply-start-width-after-skipped-text.html
+/sdcard/android/layout_tests/fast/text/align-center-rtl-spill.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/rtl-border-collapsing.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/equal-precedence-resolution.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/border-collapsing-head-foot.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/004.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/003.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/002.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/001.html
+/sdcard/android/layout_tests/fast/table/wide-column.html
+/sdcard/android/layout_tests/fast/table/wide-colspan.html
+/sdcard/android/layout_tests/fast/table/vertical-align-baseline.html
+/sdcard/android/layout_tests/fast/table/vertical-align-baseline-readjust.html
+/sdcard/android/layout_tests/fast/table/unused-percent-heights.html
+/sdcard/android/layout_tests/fast/table/unbreakable-images-quirk.html
+/sdcard/android/layout_tests/fast/table/text-field-baseline.html
+/sdcard/android/layout_tests/fast/table/tableInsideCaption.html
+/sdcard/android/layout_tests/fast/table/table-hspace-align-center.html
+/sdcard/android/layout_tests/fast/table/table-display-types.html
+/sdcard/android/layout_tests/fast/table/table-display-types-strict.html
+/sdcard/android/layout_tests/fast/table/stale-grid-crash.html
+/sdcard/android/layout_tests/fast/table/spanOverlapRepaint.html
+/sdcard/android/layout_tests/fast/table/rules-attr-dynchange2.html
+/sdcard/android/layout_tests/fast/table/rules-attr-dynchange1.html
+/sdcard/android/layout_tests/fast/table/rtl-cell-display-none-assert.html
+/sdcard/android/layout_tests/fast/table/rowspan-paint-order.html
+/sdcard/android/layout_tests/fast/table/rowindex.html
+/sdcard/android/layout_tests/fast/table/row-height-recalc.html
+/sdcard/android/layout_tests/fast/table/replaced-percent-height.html
+/sdcard/android/layout_tests/fast/table/remove-td-display-none.html
+/sdcard/android/layout_tests/fast/table/prepend-in-anonymous-table.html
+/sdcard/android/layout_tests/fast/table/percent-widths-stretch.html
+/sdcard/android/layout_tests/fast/table/percent-heights.html
+/sdcard/android/layout_tests/fast/table/overflowHidden.html
+/sdcard/android/layout_tests/fast/table/nobr.html
+/sdcard/android/layout_tests/fast/table/nested-percent-height-table.html
+/sdcard/android/layout_tests/fast/table/multiple-percent-height-rows.html
+/sdcard/android/layout_tests/fast/table/max-width-integer-overflow.html
+/sdcard/android/layout_tests/fast/table/large-width.html
+/sdcard/android/layout_tests/fast/table/invisible-cell-background.html
+/sdcard/android/layout_tests/fast/table/insert-row-before-form.html
+/sdcard/android/layout_tests/fast/table/insert-cell-before-form.html
+/sdcard/android/layout_tests/fast/table/insert-before-anonymous-ancestors.html
+/sdcard/android/layout_tests/fast/table/inline-form-assert.html
+/sdcard/android/layout_tests/fast/table/height-percent-test.html
+/sdcard/android/layout_tests/fast/table/growCellForImageQuirk.html
+/sdcard/android/layout_tests/fast/table/giantRowspan2.html
+/sdcard/android/layout_tests/fast/table/giantRowspan.html
+/sdcard/android/layout_tests/fast/table/giantCellspacing.html
+/sdcard/android/layout_tests/fast/table/generated-caption.html
+/sdcard/android/layout_tests/fast/table/frame-and-rules.html
+/sdcard/android/layout_tests/fast/table/form-with-table-style.html
+/sdcard/android/layout_tests/fast/table/floating-th.html
+/sdcard/android/layout_tests/fast/table/fixed-with-auto-with-colspan.html
+/sdcard/android/layout_tests/fast/table/fixed-table-non-cell-in-row.html
+/sdcard/android/layout_tests/fast/table/fixed-nested.html
+/sdcard/android/layout_tests/fast/table/empty-table-percent-height.html
+/sdcard/android/layout_tests/fast/table/empty-section-crash.html
+/sdcard/android/layout_tests/fast/table/empty-row-crash.html
+/sdcard/android/layout_tests/fast/table/empty-cells.html
+/sdcard/android/layout_tests/fast/table/edge-offsets.html
+/sdcard/android/layout_tests/fast/table/dynamic-cellpadding.html
+/sdcard/android/layout_tests/fast/table/div-as-col-span.html
+/sdcard/android/layout_tests/fast/table/colgroup-spanning-groups-rules.html
+/sdcard/android/layout_tests/fast/table/colgroup-preceded-by-caption.html
+/sdcard/android/layout_tests/fast/table/click-near-anonymous-table.html
+/sdcard/android/layout_tests/fast/table/cellindex.html
+/sdcard/android/layout_tests/fast/table/cell-pref-width-invalidation.html
+/sdcard/android/layout_tests/fast/table/cell-width-auto.html
+/sdcard/android/layout_tests/fast/table/cell-absolute-child.html
+/sdcard/android/layout_tests/fast/table/caption-relayout.html
+/sdcard/android/layout_tests/fast/table/auto-with-percent-height.html
+/sdcard/android/layout_tests/fast/table/append-cells2.html
+/sdcard/android/layout_tests/fast/table/append-cells.html
+/sdcard/android/layout_tests/fast/table/add-before-anonymous-child.html
+/sdcard/android/layout_tests/fast/table/absolute-table-at-bottom.html
+/sdcard/android/layout_tests/fast/table/100-percent-cell-width.html
+/sdcard/android/layout_tests/fast/table/041.html
+/sdcard/android/layout_tests/fast/table/040.html
+/sdcard/android/layout_tests/fast/table/039.html
+/sdcard/android/layout_tests/fast/table/038.html
+/sdcard/android/layout_tests/fast/table/037.xml
+/sdcard/android/layout_tests/fast/table/036.html
+/sdcard/android/layout_tests/fast/table/035.html
+/sdcard/android/layout_tests/fast/table/034.html
+/sdcard/android/layout_tests/fast/table/033.html
+/sdcard/android/layout_tests/fast/table/032.html
+/sdcard/android/layout_tests/fast/table/031.html
+/sdcard/android/layout_tests/fast/table/030.html
+/sdcard/android/layout_tests/fast/table/029.html
+/sdcard/android/layout_tests/fast/table/028.html
+/sdcard/android/layout_tests/fast/table/027.html
+/sdcard/android/layout_tests/fast/table/026.html
+/sdcard/android/layout_tests/fast/table/025.html
+/sdcard/android/layout_tests/fast/table/024.html
+/sdcard/android/layout_tests/fast/table/023.html
+/sdcard/android/layout_tests/fast/table/022.html
+/sdcard/android/layout_tests/fast/table/021.html
+/sdcard/android/layout_tests/fast/table/020.html
+/sdcard/android/layout_tests/fast/table/018.html
+/sdcard/android/layout_tests/fast/table/017.html
+/sdcard/android/layout_tests/fast/table/016.html
+/sdcard/android/layout_tests/fast/table/015.html
+/sdcard/android/layout_tests/fast/table/014.html
+/sdcard/android/layout_tests/fast/table/013.html
+/sdcard/android/layout_tests/fast/table/012.html
+/sdcard/android/layout_tests/fast/table/011.html
+/sdcard/android/layout_tests/fast/table/010.html
+/sdcard/android/layout_tests/fast/table/009.html
+/sdcard/android/layout_tests/fast/table/008.html
+/sdcard/android/layout_tests/fast/table/007.html
+/sdcard/android/layout_tests/fast/table/006.html
+/sdcard/android/layout_tests/fast/table/005.html
+/sdcard/android/layout_tests/fast/table/004.html
+/sdcard/android/layout_tests/fast/table/003.html
+/sdcard/android/layout_tests/fast/table/002.html
+/sdcard/android/layout_tests/fast/table/001.html
+/sdcard/android/layout_tests/fast/selectors/unqualified-hover-strict.html
+/sdcard/android/layout_tests/fast/selectors/unqualified-hover-quirks.html
+/sdcard/android/layout_tests/fast/selectors/nondeterministic-combinators.html
+/sdcard/android/layout_tests/fast/selectors/lang-vs-xml-lang.html
+/sdcard/android/layout_tests/fast/selectors/lang-inheritance2.html
+/sdcard/android/layout_tests/fast/selectors/lang-inheritance.html
+/sdcard/android/layout_tests/fast/selectors/177b.html
+/sdcard/android/layout_tests/fast/selectors/177a.html
+/sdcard/android/layout_tests/fast/selectors/175c.html
+/sdcard/android/layout_tests/fast/selectors/175b.html
+/sdcard/android/layout_tests/fast/selectors/175a.html
+/sdcard/android/layout_tests/fast/selectors/170d.html
+/sdcard/android/layout_tests/fast/selectors/170c.html
+/sdcard/android/layout_tests/fast/selectors/170b.html
+/sdcard/android/layout_tests/fast/selectors/170a.html
+/sdcard/android/layout_tests/fast/selectors/170.html
+/sdcard/android/layout_tests/fast/selectors/169a.html
+/sdcard/android/layout_tests/fast/selectors/169.html
+/sdcard/android/layout_tests/fast/selectors/168a.html
+/sdcard/android/layout_tests/fast/selectors/168.html
+/sdcard/android/layout_tests/fast/selectors/167a.html
+/sdcard/android/layout_tests/fast/selectors/167.html
+/sdcard/android/layout_tests/fast/selectors/166a.html
+/sdcard/android/layout_tests/fast/selectors/166.html
+/sdcard/android/layout_tests/fast/selectors/160.html
+/sdcard/android/layout_tests/fast/selectors/159.html
+/sdcard/android/layout_tests/fast/selectors/158.html
+/sdcard/android/layout_tests/fast/selectors/157.html
+/sdcard/android/layout_tests/fast/selectors/156b.html
+/sdcard/android/layout_tests/fast/selectors/155d.html
+/sdcard/android/layout_tests/fast/selectors/155c.html
+/sdcard/android/layout_tests/fast/selectors/155b.html
+/sdcard/android/layout_tests/fast/selectors/155a.html
+/sdcard/android/layout_tests/fast/selectors/155.html
+/sdcard/android/layout_tests/fast/selectors/154.html
+/sdcard/android/layout_tests/fast/selectors/090b.html
+/sdcard/android/layout_tests/fast/selectors/089.html
+/sdcard/android/layout_tests/fast/selectors/088b.html
+/sdcard/android/layout_tests/fast/selectors/087b.html
+/sdcard/android/layout_tests/fast/selectors/083.html
+/sdcard/android/layout_tests/fast/selectors/078b.html
+/sdcard/android/layout_tests/fast/selectors/077b.html
+/sdcard/android/layout_tests/fast/selectors/077.html
+/sdcard/android/layout_tests/fast/selectors/072b.html
+/sdcard/android/layout_tests/fast/selectors/072.html
+/sdcard/android/layout_tests/fast/selectors/066b.html
+/sdcard/android/layout_tests/fast/selectors/066.html
+/sdcard/android/layout_tests/fast/selectors/065.html
+/sdcard/android/layout_tests/fast/selectors/064.html
+/sdcard/android/layout_tests/fast/selectors/063.html
+/sdcard/android/layout_tests/fast/selectors/062.html
+/sdcard/android/layout_tests/fast/selectors/061.html
+/sdcard/android/layout_tests/fast/selectors/060.html
+/sdcard/android/layout_tests/fast/selectors/059.html
+/sdcard/android/layout_tests/fast/selectors/058.html
+/sdcard/android/layout_tests/fast/selectors/056.html
+/sdcard/android/layout_tests/fast/selectors/054.html
+/sdcard/android/layout_tests/fast/selectors/046.html
+/sdcard/android/layout_tests/fast/selectors/045c.html
+/sdcard/android/layout_tests/fast/selectors/045b.html
+/sdcard/android/layout_tests/fast/selectors/045.html
+/sdcard/android/layout_tests/fast/selectors/044d.html
+/sdcard/android/layout_tests/fast/selectors/044c.html
+/sdcard/android/layout_tests/fast/selectors/044b.html
+/sdcard/android/layout_tests/fast/selectors/044.html
+/sdcard/android/layout_tests/fast/selectors/043b.html
+/sdcard/android/layout_tests/fast/selectors/043.html
+/sdcard/android/layout_tests/fast/selectors/042.html
+/sdcard/android/layout_tests/fast/selectors/041.html
+/sdcard/android/layout_tests/fast/selectors/040.html
+/sdcard/android/layout_tests/fast/selectors/039b.html
+/sdcard/android/layout_tests/fast/selectors/039.html
+/sdcard/android/layout_tests/fast/selectors/038.html
+/sdcard/android/layout_tests/fast/selectors/034.html
+/sdcard/android/layout_tests/fast/selectors/032.html
+/sdcard/android/layout_tests/fast/selectors/027.html
+/sdcard/android/layout_tests/fast/selectors/021b.html
+/sdcard/android/layout_tests/fast/selectors/021.html
+/sdcard/android/layout_tests/fast/selectors/020.html
+/sdcard/android/layout_tests/fast/selectors/019.html
+/sdcard/android/layout_tests/fast/selectors/018b.html
+/sdcard/android/layout_tests/fast/selectors/018.html
+/sdcard/android/layout_tests/fast/selectors/017.html
+/sdcard/android/layout_tests/fast/selectors/016.html
+/sdcard/android/layout_tests/fast/selectors/015.html
+/sdcard/android/layout_tests/fast/selectors/014.html
+/sdcard/android/layout_tests/fast/selectors/013.html
+/sdcard/android/layout_tests/fast/selectors/012.html
+/sdcard/android/layout_tests/fast/selectors/011.html
+/sdcard/android/layout_tests/fast/selectors/010.html
+/sdcard/android/layout_tests/fast/selectors/009.html
+/sdcard/android/layout_tests/fast/selectors/008.html
+/sdcard/android/layout_tests/fast/selectors/007b.html
+/sdcard/android/layout_tests/fast/selectors/007a.html
+/sdcard/android/layout_tests/fast/selectors/006.html
+/sdcard/android/layout_tests/fast/selectors/005.html
+/sdcard/android/layout_tests/fast/selectors/004.html
+/sdcard/android/layout_tests/fast/selectors/003.html
+/sdcard/android/layout_tests/fast/selectors/002.html
+/sdcard/android/layout_tests/fast/selectors/001.html
+/sdcard/android/layout_tests/fast/runin/001.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-textfield.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-textarea.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-searchfield.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-radio.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-menulist.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-image.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-checkbox.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-button.html
+/sdcard/android/layout_tests/fast/replaced/three-selects-break.html
+/sdcard/android/layout_tests/fast/replaced/selection-rect.html
+/sdcard/android/layout_tests/fast/replaced/selection-rect-in-table-cell.html
+/sdcard/android/layout_tests/fast/replaced/replaced-child-of-absolute-with-auto-height.html
+/sdcard/android/layout_tests/fast/replaced/replaced-breaking.html
+/sdcard/android/layout_tests/fast/replaced/replaced-breaking-mixture.html
+/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block.html
+/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block-widget.html
+/sdcard/android/layout_tests/fast/replaced/pdf-as-image.html
+/sdcard/android/layout_tests/fast/replaced/object-align-hspace-vspace.html
+/sdcard/android/layout_tests/fast/replaced/minwidth-pxs.html
+/sdcard/android/layout_tests/fast/replaced/minwidth-percent.html
+/sdcard/android/layout_tests/fast/replaced/minheight-pxs.html
+/sdcard/android/layout_tests/fast/replaced/minheight-percent.html
+/sdcard/android/layout_tests/fast/replaced/maxwidth-pxs.html
+/sdcard/android/layout_tests/fast/replaced/maxwidth-percent.html
+/sdcard/android/layout_tests/fast/replaced/maxheight-pxs.html
+/sdcard/android/layout_tests/fast/replaced/maxheight-percent.html
+/sdcard/android/layout_tests/fast/replaced/max-width-percent.html
+/sdcard/android/layout_tests/fast/replaced/inline-box-wrapper-handover.html
+/sdcard/android/layout_tests/fast/replaced/image-tag.html
+/sdcard/android/layout_tests/fast/replaced/image-solid-color-with-alpha.html
+/sdcard/android/layout_tests/fast/replaced/image-sizing.html
+/sdcard/android/layout_tests/fast/replaced/image-resize-width.html
+/sdcard/android/layout_tests/fast/replaced/image-onload.html
+/sdcard/android/layout_tests/fast/replaced/applet-rendering-java-disabled.html
+/sdcard/android/layout_tests/fast/replaced/applet-disabled-positioned.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-with-auto-width-and-left-and-right.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-with-auto-height-and-top-and-bottom.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-percentage-width.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-percentage-height.html
+/sdcard/android/layout_tests/fast/replaced/absolute-image-sizing.html
+/sdcard/android/layout_tests/fast/replaced/008.html
+/sdcard/android/layout_tests/fast/replaced/007.html
+/sdcard/android/layout_tests/fast/replaced/006.html
+/sdcard/android/layout_tests/fast/replaced/005.html
+/sdcard/android/layout_tests/fast/replaced/004.html
+/sdcard/android/layout_tests/fast/replaced/003.html
+/sdcard/android/layout_tests/fast/replaced/002.html
+/sdcard/android/layout_tests/fast/replaced/001.html
+/sdcard/android/layout_tests/fast/repaint/transform-translate.html
+/sdcard/android/layout_tests/fast/repaint/text-shadow.html
+/sdcard/android/layout_tests/fast/repaint/text-shadow-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/text-selection-rect-in-overflow.html
+/sdcard/android/layout_tests/fast/repaint/text-selection-rect-in-overflow-2.html
+/sdcard/android/layout_tests/fast/repaint/table-two-pass-layout-overpaint.html
+/sdcard/android/layout_tests/fast/repaint/table-section-repaint.html
+/sdcard/android/layout_tests/fast/repaint/table-section-overflow.html
+/sdcard/android/layout_tests/fast/repaint/table-row.html
+/sdcard/android/layout_tests/fast/repaint/table-outer-border.html
+/sdcard/android/layout_tests/fast/repaint/table-extra-bottom-grow.html
+/sdcard/android/layout_tests/fast/repaint/table-collapsed-border.html
+/sdcard/android/layout_tests/fast/repaint/table-col-background.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-vertical-overflow.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-move.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-collapsed-border.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-skipped.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip-3.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip-2.html
+/sdcard/android/layout_tests/fast/repaint/static-to-positioned.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-vertical.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-strict-vertical.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-strict-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/selection-gap-overflow-scroll.html
+/sdcard/android/layout_tests/fast/repaint/selection-after-remove.html
+/sdcard/android/layout_tests/fast/repaint/selection-after-delete.html
+/sdcard/android/layout_tests/fast/repaint/repaint-resized-overflow.html
+/sdcard/android/layout_tests/fast/repaint/renderer-destruction-by-invalidateSelection-crash.html
+/sdcard/android/layout_tests/fast/repaint/overflow-scroll-delete.html
+/sdcard/android/layout_tests/fast/repaint/overflow-outline-repaint.html
+/sdcard/android/layout_tests/fast/repaint/overflow-into-content.html
+/sdcard/android/layout_tests/fast/repaint/overflow-delete-line.html
+/sdcard/android/layout_tests/fast/repaint/overflow-clip-subtree-layout.html
+/sdcard/android/layout_tests/fast/repaint/outline-shrinking.html
+/sdcard/android/layout_tests/fast/repaint/outline-repaint-glitch.html
+/sdcard/android/layout_tests/fast/repaint/outline-inset.html
+/sdcard/android/layout_tests/fast/repaint/make-children-non-inline.html
+/sdcard/android/layout_tests/fast/repaint/list-marker.html
+/sdcard/android/layout_tests/fast/repaint/list-marker-2.html
+/sdcard/android/layout_tests/fast/repaint/lines-with-layout-delta.html
+/sdcard/android/layout_tests/fast/repaint/line-overflow.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-9.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-8.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-7.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-6.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-5.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-4.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-3.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-2.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-10.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-1.html
+/sdcard/android/layout_tests/fast/repaint/layout-state-relative.html
+/sdcard/android/layout_tests/fast/repaint/layout-state-only-positioned.html
+/sdcard/android/layout_tests/fast/repaint/layer-visibility.html
+/sdcard/android/layout_tests/fast/repaint/layer-outline.html
+/sdcard/android/layout_tests/fast/repaint/layer-outline-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/layer-hide-when-needs-layout.html
+/sdcard/android/layout_tests/fast/repaint/layer-full-repaint.html
+/sdcard/android/layout_tests/fast/repaint/layer-child-outline.html
+/sdcard/android/layout_tests/fast/repaint/invisible-objects.html
+/sdcard/android/layout_tests/fast/repaint/intermediate-layout-position.html
+/sdcard/android/layout_tests/fast/repaint/intermediate-layout-position-clip.html
+/sdcard/android/layout_tests/fast/repaint/inline-outline-repaint.html
+/sdcard/android/layout_tests/fast/repaint/inline-block-overflow.html
+/sdcard/android/layout_tests/fast/repaint/focus-ring.html
+/sdcard/android/layout_tests/fast/repaint/focus-layers.html
+/sdcard/android/layout_tests/fast/repaint/float-overflow.html
+/sdcard/android/layout_tests/fast/repaint/float-overflow-right.html
+/sdcard/android/layout_tests/fast/repaint/float-move-during-layout.html
+/sdcard/android/layout_tests/fast/repaint/flexible-box-overflow.html
+/sdcard/android/layout_tests/fast/repaint/flexible-box-overflow-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/fixed.html
+/sdcard/android/layout_tests/fast/repaint/erase-overflow.html
+/sdcard/android/layout_tests/fast/repaint/delete-into-nested-block.html
+/sdcard/android/layout_tests/fast/repaint/control-clip.html
+/sdcard/android/layout_tests/fast/repaint/continuation-after-outline.html
+/sdcard/android/layout_tests/fast/repaint/content-into-overflow.html
+/sdcard/android/layout_tests/fast/repaint/containing-block-position-change.html
+/sdcard/android/layout_tests/fast/repaint/clipped-relative.html
+/sdcard/android/layout_tests/fast/repaint/clip-with-layout-delta.html
+/sdcard/android/layout_tests/fast/repaint/caret-outside-block.html
+/sdcard/android/layout_tests/fast/repaint/button-spurious-layout-hint.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-7235.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6473.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6388.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6278.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-5699.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-3509.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-v.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-h.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-dynamic.html
+/sdcard/android/layout_tests/fast/repaint/border-repaint-glitch.html
+/sdcard/android/layout_tests/fast/repaint/border-radius-repaint.html
+/sdcard/android/layout_tests/fast/repaint/border-fit-lines.html
+/sdcard/android/layout_tests/fast/repaint/body-background-image.html
+/sdcard/android/layout_tests/fast/repaint/backgroundSizeRepaint.html
+/sdcard/android/layout_tests/fast/repaint/4776765.html
+/sdcard/android/layout_tests/fast/repaint/4774354.html
+/sdcard/android/layout_tests/fast/reflections/table-cell.html
+/sdcard/android/layout_tests/fast/reflections/reflection-nesting.html
+/sdcard/android/layout_tests/fast/reflections/reflection-direction.html
+/sdcard/android/layout_tests/fast/reflections/inline-crash.html
+/sdcard/android/layout_tests/fast/parser/title-error-test.html
+/sdcard/android/layout_tests/fast/parser/style-script-head-test.html
+/sdcard/android/layout_tests/fast/parser/parseCommentsInTitles.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-textarea.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/fonts.html
+/sdcard/android/layout_tests/fast/parser/external-entities-in-xslt.xml
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-textarea.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/document-write-option.html
+/sdcard/android/layout_tests/fast/parser/comments.html
+/sdcard/android/layout_tests/fast/parser/comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/comment-in-script.html
+/sdcard/android/layout_tests/fast/parser/broken-comments-vs-parsing-mode.html
+/sdcard/android/layout_tests/fast/parser/bad-xml-slash.html
+/sdcard/android/layout_tests/fast/parser/001.html
+/sdcard/android/layout_tests/fast/overflow/unreachable-overflow-rtl-bug.html
+/sdcard/android/layout_tests/fast/overflow/unreachable-content-test.html
+/sdcard/android/layout_tests/fast/overflow/table-overflow-float.html
+/sdcard/android/layout_tests/fast/overflow/scrollRevealButton.html
+/sdcard/android/layout_tests/fast/overflow/scrollbar-position-update.html
+/sdcard/android/layout_tests/fast/overflow/scroll-nested-positioned-layer-in-overflow.html
+/sdcard/android/layout_tests/fast/overflow/position-relative.html
+/sdcard/android/layout_tests/fast/overflow/overflow_hidden.html
+/sdcard/android/layout_tests/fast/overflow/overflow-x-y.html
+/sdcard/android/layout_tests/fast/overflow/overflow-text-hit-testing.html
+/sdcard/android/layout_tests/fast/overflow/overflow-rtl.html
+/sdcard/android/layout_tests/fast/overflow/overflow-rtl-inline-scrollbar.html
+/sdcard/android/layout_tests/fast/overflow/overflow-focus-ring.html
+/sdcard/android/layout_tests/fast/overflow/overflow-auto-table.html
+/sdcard/android/layout_tests/fast/overflow/overflow-auto-position-absolute.html
+/sdcard/android/layout_tests/fast/overflow/infiniteRecursionGuard.html
+/sdcard/android/layout_tests/fast/overflow/infiniteRecursion.html
+/sdcard/android/layout_tests/fast/overflow/image-selection-highlight.html
+/sdcard/android/layout_tests/fast/overflow/hit-test-overflow-controls.html
+/sdcard/android/layout_tests/fast/overflow/hidden-scrollbar-resize.html
+/sdcard/android/layout_tests/fast/overflow/float-in-relpositioned.html
+/sdcard/android/layout_tests/fast/overflow/dynamic-hidden.html
+/sdcard/android/layout_tests/fast/overflow/clip-rects-fixed-ancestor.html
+/sdcard/android/layout_tests/fast/overflow/childFocusRingClip.html
+/sdcard/android/layout_tests/fast/overflow/008.html
+/sdcard/android/layout_tests/fast/overflow/007.html
+/sdcard/android/layout_tests/fast/overflow/006.html
+/sdcard/android/layout_tests/fast/overflow/005.html
+/sdcard/android/layout_tests/fast/overflow/004.html
+/sdcard/android/layout_tests/fast/overflow/003.xml
+/sdcard/android/layout_tests/fast/overflow/002.html
+/sdcard/android/layout_tests/fast/overflow/001.html
+/sdcard/android/layout_tests/fast/multicol/zeroColumnCount.html
+/sdcard/android/layout_tests/fast/multicol/negativeColumnWidth.html
+/sdcard/android/layout_tests/fast/multicol/float-multicol.html
+/sdcard/android/layout_tests/fast/multicol/float-avoidance.html
+/sdcard/android/layout_tests/fast/multicol/columns-shorthand-parsing.html
+/sdcard/android/layout_tests/fast/multicol/column-rules.html
+/sdcard/android/layout_tests/fast/media/viewport-media-query.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-04.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-03.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-02.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-01.html
+/sdcard/android/layout_tests/fast/media/mq-valueless.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-05.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-04.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-03.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-02.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-01.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-05.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-04.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-03.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-02.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-01.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-09.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-08.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-07.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-06.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-05.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-04.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-03.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-02.html
+/sdcard/android/layout_tests/fast/media/mq-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/mq-min-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/mq-min-constraint.html
+/sdcard/android/layout_tests/fast/media/mq-max-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-04.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-03.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-02.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-01.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-forward-syntax.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-03.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-02.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-01.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-05.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-04.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-03.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-02.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-01.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-04.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-03.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-02.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-01.html
+/sdcard/android/layout_tests/fast/media/mq-grid-02.html
+/sdcard/android/layout_tests/fast/media/mq-grid-01.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-05.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-04.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-03.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-02.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-01.html
+/sdcard/android/layout_tests/fast/media/monochrome.html
+/sdcard/android/layout_tests/fast/media/media-type-syntax-02.html
+/sdcard/android/layout_tests/fast/media/media-type-syntax-01.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-06.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-05.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-04.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-03.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-02.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-01.html
+/sdcard/android/layout_tests/fast/media/implicit-media-all.html
+/sdcard/android/layout_tests/fast/loader/text-document-wrapping.html
+/sdcard/android/layout_tests/fast/loader/start-load-in-unload.html
+/sdcard/android/layout_tests/fast/lists/w3-list-styles.html
+/sdcard/android/layout_tests/fast/lists/scrolled-marker-paint.html
+/sdcard/android/layout_tests/fast/lists/ordered-list-with-no-ol-tag.html
+/sdcard/android/layout_tests/fast/lists/olstart.html
+/sdcard/android/layout_tests/fast/lists/ol-start-dynamic.html
+/sdcard/android/layout_tests/fast/lists/ol-display-types.html
+/sdcard/android/layout_tests/fast/lists/numeric-markers-outside-list.html
+/sdcard/android/layout_tests/fast/lists/markers-in-selection.html
+/sdcard/android/layout_tests/fast/lists/marker-image-error.html
+/sdcard/android/layout_tests/fast/lists/marker-before-empty-inline.html
+/sdcard/android/layout_tests/fast/lists/list-style-type-dynamic-change.html
+/sdcard/android/layout_tests/fast/lists/list-style-none-crash.html
+/sdcard/android/layout_tests/fast/lists/list-item-line-height.html
+/sdcard/android/layout_tests/fast/lists/li-values.html
+/sdcard/android/layout_tests/fast/lists/li-style-alpha-huge-value-crash.html
+/sdcard/android/layout_tests/fast/lists/li-br.html
+/sdcard/android/layout_tests/fast/lists/item-not-in-list-line-wrapping.html
+/sdcard/android/layout_tests/fast/lists/inlineBoxWrapperNullCheck.html
+/sdcard/android/layout_tests/fast/lists/dynamic-marker-crash.html
+/sdcard/android/layout_tests/fast/lists/drag-into-marker.html
+/sdcard/android/layout_tests/fast/lists/decimal-leading-zero.html
+/sdcard/android/layout_tests/fast/lists/big-list-marker.html
+/sdcard/android/layout_tests/fast/lists/alpha-list-wrap.html
+/sdcard/android/layout_tests/fast/lists/009.html
+/sdcard/android/layout_tests/fast/lists/008.html
+/sdcard/android/layout_tests/fast/lists/007.html
+/sdcard/android/layout_tests/fast/lists/006.html
+/sdcard/android/layout_tests/fast/lists/005.html
+/sdcard/android/layout_tests/fast/lists/004.html
+/sdcard/android/layout_tests/fast/lists/003.html
+/sdcard/android/layout_tests/fast/lists/002.html
+/sdcard/android/layout_tests/fast/lists/001.html
+/sdcard/android/layout_tests/fast/layers/zindex-ridonkulous.html
+/sdcard/android/layout_tests/fast/layers/zindex-inherit.html
+/sdcard/android/layout_tests/fast/layers/scroll-rect-to-visible.html
+/sdcard/android/layout_tests/fast/layers/remove-layer-with-nested-stacking.html
+/sdcard/android/layout_tests/fast/layers/positioned-inside-root-with-margins.html
+/sdcard/android/layout_tests/fast/layers/overflow-scroll-auto-switch.html
+/sdcard/android/layout_tests/fast/layers/opacity-stacking.html
+/sdcard/android/layout_tests/fast/layers/opacity-outline.html
+/sdcard/android/layout_tests/fast/layers/layer-visibility.html
+/sdcard/android/layout_tests/fast/layers/layer-visibility-sublayer.html
+/sdcard/android/layout_tests/fast/layers/layer-content-visibility-change.html
+/sdcard/android/layout_tests/fast/layers/add-layer-with-nested-stacking.html
+/sdcard/android/layout_tests/fast/js/missing-style-end-tag-js.html
+/sdcard/android/layout_tests/fast/invalid/td-inside-object.html
+/sdcard/android/layout_tests/fast/invalid/table-residual-style-crash.html
+/sdcard/android/layout_tests/fast/invalid/table-inside-stray-table-content.html
+/sdcard/android/layout_tests/fast/invalid/residual-style.html
+/sdcard/android/layout_tests/fast/invalid/nestedh3s.html
+/sdcard/android/layout_tests/fast/invalid/missing-font-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/missing-dt-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/missing-dl-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/missing-address-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/junk-data.xml
+/sdcard/android/layout_tests/fast/invalid/021.html
+/sdcard/android/layout_tests/fast/invalid/020.xml
+/sdcard/android/layout_tests/fast/invalid/019.html
+/sdcard/android/layout_tests/fast/invalid/018.html
+/sdcard/android/layout_tests/fast/invalid/017.html
+/sdcard/android/layout_tests/fast/invalid/016.html
+/sdcard/android/layout_tests/fast/invalid/015.html
+/sdcard/android/layout_tests/fast/invalid/014.html
+/sdcard/android/layout_tests/fast/invalid/013.html
+/sdcard/android/layout_tests/fast/invalid/012.html
+/sdcard/android/layout_tests/fast/invalid/011.html
+/sdcard/android/layout_tests/fast/invalid/010.html
+/sdcard/android/layout_tests/fast/invalid/009.html
+/sdcard/android/layout_tests/fast/invalid/008.html
+/sdcard/android/layout_tests/fast/invalid/007.html
+/sdcard/android/layout_tests/fast/invalid/006.html
+/sdcard/android/layout_tests/fast/invalid/005.html
+/sdcard/android/layout_tests/fast/invalid/004.html
+/sdcard/android/layout_tests/fast/invalid/003.html
+/sdcard/android/layout_tests/fast/invalid/002.html
+/sdcard/android/layout_tests/fast/invalid/001.html
+/sdcard/android/layout_tests/fast/inspector/style.html
+/sdcard/android/layout_tests/fast/inspector/matchedrules.html
+/sdcard/android/layout_tests/fast/innerHTML/006.html
+/sdcard/android/layout_tests/fast/innerHTML/003.html
+/sdcard/android/layout_tests/fast/innerHTML/002.html
+/sdcard/android/layout_tests/fast/innerHTML/001.html
+/sdcard/android/layout_tests/fast/inline-block/tricky-baseline.html
+/sdcard/android/layout_tests/fast/inline-block/overflow-clip.html
+/sdcard/android/layout_tests/fast/inline-block/inline-block-vertical-align.html
+/sdcard/android/layout_tests/fast/inline-block/contenteditable-baseline.html
+/sdcard/android/layout_tests/fast/inline-block/14498-positionForCoordinates.html
+/sdcard/android/layout_tests/fast/inline-block/006.html
+/sdcard/android/layout_tests/fast/inline-block/005.html
+/sdcard/android/layout_tests/fast/inline-block/004.html
+/sdcard/android/layout_tests/fast/inline-block/003.html
+/sdcard/android/layout_tests/fast/inline-block/002.html
+/sdcard/android/layout_tests/fast/inline-block/001.html
+/sdcard/android/layout_tests/fast/inline/styledEmptyInlinesWithBRs.html
+/sdcard/android/layout_tests/fast/inline/positionedLifetime.html
+/sdcard/android/layout_tests/fast/inline/percentage-margins.html
+/sdcard/android/layout_tests/fast/inline/outline-continuations.html
+/sdcard/android/layout_tests/fast/inline/inline-text-quirk-bpm.html
+/sdcard/android/layout_tests/fast/inline/inline-padding-disables-text-quirk.html
+/sdcard/android/layout_tests/fast/inline/inline-borders-with-bidi-override.html
+/sdcard/android/layout_tests/fast/inline/emptyInlinesWithinLists.html
+/sdcard/android/layout_tests/fast/inline/drawStyledEmptyInlinesWithWS.html
+/sdcard/android/layout_tests/fast/inline/drawStyledEmptyInlines.html
+/sdcard/android/layout_tests/fast/inline/dirtyLinesForInline.html
+/sdcard/android/layout_tests/fast/inline/continuation-outlines.html
+/sdcard/android/layout_tests/fast/inline/continuation-outlines-with-layers.html
+/sdcard/android/layout_tests/fast/inline/002.html
+/sdcard/android/layout_tests/fast/inline/001.html
+/sdcard/android/layout_tests/fast/images/svg-as-tiled-background.html
+/sdcard/android/layout_tests/fast/images/svg-as-relative-image.html
+/sdcard/android/layout_tests/fast/images/svg-as-image.html
+/sdcard/android/layout_tests/fast/images/svg-as-background.html
+/sdcard/android/layout_tests/fast/images/pdf-as-tiled-background.html
+/sdcard/android/layout_tests/fast/images/pdf-as-image.html
+/sdcard/android/layout_tests/fast/images/pdf-as-image-landscape.html
+/sdcard/android/layout_tests/fast/images/pdf-as-background.html
+/sdcard/android/layout_tests/fast/images/object-image.html
+/sdcard/android/layout_tests/fast/images/image-map-anchor-children.html
+/sdcard/android/layout_tests/fast/images/image-in-map.html
+/sdcard/android/layout_tests/fast/images/favicon-as-image.html
+/sdcard/android/layout_tests/fast/images/embed-image.html
+/sdcard/android/layout_tests/fast/images/animated-gif-with-offsets.html
+/sdcard/android/layout_tests/fast/html/marquee-scroll.html
+/sdcard/android/layout_tests/fast/html/listing.html
+/sdcard/android/layout_tests/fast/html/link-rel-stylesheet.html
+/sdcard/android/layout_tests/fast/html/keygen.html
+/sdcard/android/layout_tests/fast/history/history_reload.html
+/sdcard/android/layout_tests/fast/history/clicked-link-is-visited.html
+/sdcard/android/layout_tests/fast/frames/viewsource-attribute.html
+/sdcard/android/layout_tests/fast/frames/valid.html
+/sdcard/android/layout_tests/fast/frames/onlyCommentInIFrame.html
+/sdcard/android/layout_tests/fast/frames/no-frame-borders.html
+/sdcard/android/layout_tests/fast/frames/invalid.html
+/sdcard/android/layout_tests/fast/frames/inline-object-inside-frameset.html
+/sdcard/android/layout_tests/fast/frames/iframe-with-frameborder.html
+/sdcard/android/layout_tests/fast/frames/iframe-text-contents.html
+/sdcard/android/layout_tests/fast/frames/iframe-scrolling-attribute.html
+/sdcard/android/layout_tests/fast/frames/frameset-style-recalc.html
+/sdcard/android/layout_tests/fast/frames/frameElement-iframe.html
+/sdcard/android/layout_tests/fast/frames/frameElement-frame.html
+/sdcard/android/layout_tests/fast/frames/frame-src-attribute.html
+/sdcard/android/layout_tests/fast/frames/frame-set-whitespace-attributes.html
+/sdcard/android/layout_tests/fast/frames/frame-scrolling-attribute.html
+/sdcard/android/layout_tests/fast/frames/frame-navigation.html
+/sdcard/android/layout_tests/fast/frames/frame-length-fractional.html
+/sdcard/android/layout_tests/fast/frames/frame-element-name.html
+/sdcard/android/layout_tests/fast/frames/empty-cols-attribute.html
+/sdcard/android/layout_tests/fast/frames/contentWindow_iFrame.html
+/sdcard/android/layout_tests/fast/frames/contentWindow_Frame.html
+/sdcard/android/layout_tests/fast/frames/calculate-round.html
+/sdcard/android/layout_tests/fast/frames/calculate-relative.html
+/sdcard/android/layout_tests/fast/frames/calculate-percentage.html
+/sdcard/android/layout_tests/fast/frames/calculate-order.html
+/sdcard/android/layout_tests/fast/frames/calculate-fixed.html
+/sdcard/android/layout_tests/fast/frames/002.html
+/sdcard/android/layout_tests/fast/frames/001.html
+/sdcard/android/layout_tests/fast/forms/thumbslider-no-parent-slider.html
+/sdcard/android/layout_tests/fast/forms/thumbslider-crash.html
+/sdcard/android/layout_tests/fast/forms/textfield-outline.html
+/sdcard/android/layout_tests/fast/forms/textfield-drag-into-disabled.html
+/sdcard/android/layout_tests/fast/forms/textAreaLineHeight.html
+/sdcard/android/layout_tests/fast/forms/textarea-width.html
+/sdcard/android/layout_tests/fast/forms/textarea-setinnerhtml.html
+/sdcard/android/layout_tests/fast/forms/textarea-scrolled-type.html
+/sdcard/android/layout_tests/fast/forms/textarea-rows-cols.html
+/sdcard/android/layout_tests/fast/forms/slider-thumb-shared-style.html
+/sdcard/android/layout_tests/fast/forms/slider-padding.html
+/sdcard/android/layout_tests/fast/forms/select-writing-direction-natural.html
+/sdcard/android/layout_tests/fast/forms/select-size.html
+/sdcard/android/layout_tests/fast/forms/select-selected.html
+/sdcard/android/layout_tests/fast/forms/select-list-box-with-height.html
+/sdcard/android/layout_tests/fast/forms/select-initial-position.html
+/sdcard/android/layout_tests/fast/forms/select-display-none-style-resolve.html
+/sdcard/android/layout_tests/fast/forms/select-disabled-appearance.html
+/sdcard/android/layout_tests/fast/forms/select-change-popup-to-listbox.html
+/sdcard/android/layout_tests/fast/forms/select-change-listbox-to-popup.html
+/sdcard/android/layout_tests/fast/forms/select-change-listbox-size.html
+/sdcard/android/layout_tests/fast/forms/select-block-background.html
+/sdcard/android/layout_tests/fast/forms/select-baseline.html
+/sdcard/android/layout_tests/fast/forms/select-align.html
+/sdcard/android/layout_tests/fast/forms/search-placeholder-value-changed.html
+/sdcard/android/layout_tests/fast/forms/search-display-none-cancel-button.html
+/sdcard/android/layout_tests/fast/forms/radio_checked_dynamic.html
+/sdcard/android/layout_tests/fast/forms/radio_checked.html
+/sdcard/android/layout_tests/fast/forms/radio-nested-labels.html
+/sdcard/android/layout_tests/fast/forms/radio-attr-order.html
+/sdcard/android/layout_tests/fast/forms/preserveFormDuringResidualStyle.html
+/sdcard/android/layout_tests/fast/forms/plaintext-mode-2.html
+/sdcard/android/layout_tests/fast/forms/placeholder-set-attribute.html
+/sdcard/android/layout_tests/fast/forms/placeholder-pseudo-style.html
+/sdcard/android/layout_tests/fast/forms/password-placeholder.html
+/sdcard/android/layout_tests/fast/forms/password-placeholder-text-security.html
+/sdcard/android/layout_tests/fast/forms/option-text-clip.html
+/sdcard/android/layout_tests/fast/forms/option-strip-whitespace.html
+/sdcard/android/layout_tests/fast/forms/option-script.html
+/sdcard/android/layout_tests/fast/forms/option-index.html
+/sdcard/android/layout_tests/fast/forms/negativeLineHeight.html
+/sdcard/android/layout_tests/fast/forms/minWidthPercent.html
+/sdcard/android/layout_tests/fast/forms/menulist-width-change.html
+/sdcard/android/layout_tests/fast/forms/menulist-separator-painting.html
+/sdcard/android/layout_tests/fast/forms/menulist-restrict-line-height.html
+/sdcard/android/layout_tests/fast/forms/menulist-option-wrap.html
+/sdcard/android/layout_tests/fast/forms/menulist-no-overflow.html
+/sdcard/android/layout_tests/fast/forms/menulist-narrow-width.html
+/sdcard/android/layout_tests/fast/forms/menulist-deselect-update.html
+/sdcard/android/layout_tests/fast/forms/menulist-clip.html
+/sdcard/android/layout_tests/fast/forms/listbox-width-change.html
+/sdcard/android/layout_tests/fast/forms/listbox-selection-2.html
+/sdcard/android/layout_tests/fast/forms/listbox-scrollbar-incremental-load.html
+/sdcard/android/layout_tests/fast/forms/listbox-deselect-scroll.html
+/sdcard/android/layout_tests/fast/forms/listbox-clip.html
+/sdcard/android/layout_tests/fast/forms/input-width.html
+/sdcard/android/layout_tests/fast/forms/input-value.html
+/sdcard/android/layout_tests/fast/forms/input-type-text-min-width.html
+/sdcard/android/layout_tests/fast/forms/input-type-change2.html
+/sdcard/android/layout_tests/fast/forms/input-type-change.html
+/sdcard/android/layout_tests/fast/forms/input-text-word-wrap.html
+/sdcard/android/layout_tests/fast/forms/input-text-self-emptying-click.html
+/sdcard/android/layout_tests/fast/forms/input-text-scroll-left-on-blur.html
+/sdcard/android/layout_tests/fast/forms/input-text-paste-maxlength.html
+/sdcard/android/layout_tests/fast/forms/input-text-option-delete.html
+/sdcard/android/layout_tests/fast/forms/input-text-maxlength.html
+/sdcard/android/layout_tests/fast/forms/input-text-drag-down.html
+/sdcard/android/layout_tests/fast/forms/input-text-double-click.html
+/sdcard/android/layout_tests/fast/forms/input-text-click-outside.html
+/sdcard/android/layout_tests/fast/forms/input-text-click-inside.html
+/sdcard/android/layout_tests/fast/forms/input-table.html
+/sdcard/android/layout_tests/fast/forms/input-spaces.html
+/sdcard/android/layout_tests/fast/forms/input-readonly-empty.html
+/sdcard/android/layout_tests/fast/forms/input-readonly-dimmed.html
+/sdcard/android/layout_tests/fast/forms/input-readonly-autoscroll.html
+/sdcard/android/layout_tests/fast/forms/input-paste-undo.html
+/sdcard/android/layout_tests/fast/forms/input-no-renderer.html
+/sdcard/android/layout_tests/fast/forms/input-field-text-truncated.html
+/sdcard/android/layout_tests/fast/forms/input-double-click-selection-gap-bug.html
+/sdcard/android/layout_tests/fast/forms/input-disabled-color.html
+/sdcard/android/layout_tests/fast/forms/input-baseline.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-width.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-visibility.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-selection.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-readonly.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-preventDefault.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-height.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-focus.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-default-bkcolor.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-bkcolor.html
+/sdcard/android/layout_tests/fast/forms/input-align.html
+/sdcard/android/layout_tests/fast/forms/input-align-image.html
+/sdcard/android/layout_tests/fast/forms/indeterminate.html
+/sdcard/android/layout_tests/fast/forms/image-border.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label07.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label06.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label05.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label04.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label03.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label02.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label01.html
+/sdcard/android/layout_tests/fast/forms/hidden-listbox.html
+/sdcard/android/layout_tests/fast/forms/hidden-input-file.html
+/sdcard/android/layout_tests/fast/forms/formmove3.html
+/sdcard/android/layout_tests/fast/forms/formmove2.html
+/sdcard/android/layout_tests/fast/forms/formmove.html
+/sdcard/android/layout_tests/fast/forms/form-hides-table.html
+/sdcard/android/layout_tests/fast/forms/float-before-fieldset.html
+/sdcard/android/layout_tests/fast/forms/file-input-disabled.html
+/sdcard/android/layout_tests/fast/forms/file-input-direction.html
+/sdcard/android/layout_tests/fast/forms/fieldset-with-float.html
+/sdcard/android/layout_tests/fast/forms/fieldset-align.html
+/sdcard/android/layout_tests/fast/forms/dragging-to-file-input.html
+/sdcard/android/layout_tests/fast/forms/dragging-to-disabled-file-input.html
+/sdcard/android/layout_tests/fast/forms/disabled-select-change-index.html
+/sdcard/android/layout_tests/fast/forms/control-restrict-line-height.html
+/sdcard/android/layout_tests/fast/forms/control-clip.html
+/sdcard/android/layout_tests/fast/forms/control-clip-overflow.html
+/sdcard/android/layout_tests/fast/forms/checkbox-radio-onchange.html
+/sdcard/android/layout_tests/fast/forms/button-white-space.html
+/sdcard/android/layout_tests/fast/forms/button-text-transform.html
+/sdcard/android/layout_tests/fast/forms/button-table-styles.html
+/sdcard/android/layout_tests/fast/forms/button-submit.html
+/sdcard/android/layout_tests/fast/forms/button-sizes.html
+/sdcard/android/layout_tests/fast/forms/button-positioned.html
+/sdcard/android/layout_tests/fast/forms/button-inner-block-reuse.html
+/sdcard/android/layout_tests/fast/forms/button-generated-content.html
+/sdcard/android/layout_tests/fast/forms/button-default-title.html
+/sdcard/android/layout_tests/fast/forms/button-cannot-be-nested.html
+/sdcard/android/layout_tests/fast/forms/button-align.html
+/sdcard/android/layout_tests/fast/forms/box-shadow-override.html
+/sdcard/android/layout_tests/fast/forms/blankbuttons.html
+/sdcard/android/layout_tests/fast/forms/006.html
+/sdcard/android/layout_tests/fast/forms/005.html
+/sdcard/android/layout_tests/fast/forms/004.html
+/sdcard/android/layout_tests/fast/forms/003.html
+/sdcard/android/layout_tests/fast/forms/002.html
+/sdcard/android/layout_tests/fast/forms/001.html
+/sdcard/android/layout_tests/fast/flexbox/flex-hang.html
+/sdcard/android/layout_tests/fast/flexbox/026.html
+/sdcard/android/layout_tests/fast/flexbox/025.html
+/sdcard/android/layout_tests/fast/flexbox/024.html
+/sdcard/android/layout_tests/fast/flexbox/023.html
+/sdcard/android/layout_tests/fast/flexbox/022.html
+/sdcard/android/layout_tests/fast/flexbox/021.html
+/sdcard/android/layout_tests/fast/flexbox/020.html
+/sdcard/android/layout_tests/fast/flexbox/019.html
+/sdcard/android/layout_tests/fast/flexbox/018.html
+/sdcard/android/layout_tests/fast/flexbox/017.html
+/sdcard/android/layout_tests/fast/flexbox/016.html
+/sdcard/android/layout_tests/fast/flexbox/015.html
+/sdcard/android/layout_tests/fast/flexbox/014.html
+/sdcard/android/layout_tests/fast/flexbox/013.html
+/sdcard/android/layout_tests/fast/flexbox/012.html
+/sdcard/android/layout_tests/fast/flexbox/011.html
+/sdcard/android/layout_tests/fast/flexbox/010.html
+/sdcard/android/layout_tests/fast/flexbox/009.html
+/sdcard/android/layout_tests/fast/flexbox/008.html
+/sdcard/android/layout_tests/fast/flexbox/007.html
+/sdcard/android/layout_tests/fast/flexbox/006.html
+/sdcard/android/layout_tests/fast/flexbox/005.html
+/sdcard/android/layout_tests/fast/flexbox/004.html
+/sdcard/android/layout_tests/fast/flexbox/003.html
+/sdcard/android/layout_tests/fast/flexbox/002.html
+/sdcard/android/layout_tests/fast/flexbox/001.html
+/sdcard/android/layout_tests/fast/events/updateLayoutForHitTest.html
+/sdcard/android/layout_tests/fast/events/standalone-image-drag-to-editable.html
+/sdcard/android/layout_tests/fast/events/reveal-link-when-focused.html
+/sdcard/android/layout_tests/fast/events/onloadFrameCrash.html
+/sdcard/android/layout_tests/fast/events/onload-re-entry.html
+/sdcard/android/layout_tests/fast/events/mouseout-dead-node.html
+/sdcard/android/layout_tests/fast/events/label-focus.html
+/sdcard/android/layout_tests/fast/events/keydown-1.html
+/sdcard/android/layout_tests/fast/events/focusingUnloadedFrame.html
+/sdcard/android/layout_tests/fast/events/event-sender-mouse-moved.html
+/sdcard/android/layout_tests/fast/events/event-listener-on-link.html
+/sdcard/android/layout_tests/fast/events/context-onmousedown-event.html
+/sdcard/android/layout_tests/fast/events/autoscroll.html
+/sdcard/android/layout_tests/fast/events/attempt-scroll-with-no-scrollbars.html
+/sdcard/android/layout_tests/fast/events/5056619.html
+/sdcard/android/layout_tests/fast/encoding/xmacroman-encoding-test.html
+/sdcard/android/layout_tests/fast/encoding/utf-16-no-bom.xml
+/sdcard/android/layout_tests/fast/encoding/utf-16-little-endian.html
+/sdcard/android/layout_tests/fast/encoding/utf-16-big-endian.html
+/sdcard/android/layout_tests/fast/encoding/invalid-UTF-8.html
+/sdcard/android/layout_tests/fast/encoding/denormalised-voiced-japanese-chars.html
+/sdcard/android/layout_tests/fast/dynamic/view-overflow.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-table-cell-height.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-parent-static-y.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-no-common-root-static-y.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-boundary-percent-height.html
+/sdcard/android/layout_tests/fast/dynamic/staticY.html
+/sdcard/android/layout_tests/fast/dynamic/staticY-marking-parents-regression.html
+/sdcard/android/layout_tests/fast/dynamic/selection-highlight-adjust.html
+/sdcard/android/layout_tests/fast/dynamic/positioned-movement-with-positioned-children.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-img.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-doc.html
+/sdcard/android/layout_tests/fast/dynamic/noninlinebadness.html
+/sdcard/android/layout_tests/fast/dynamic/move-node-with-selection.html
+/sdcard/android/layout_tests/fast/dynamic/link-href-change.html
+/sdcard/android/layout_tests/fast/dynamic/layer-hit-test-crash.html
+/sdcard/android/layout_tests/fast/dynamic/insert-before-table-part-in-continuation.html
+/sdcard/android/layout_tests/fast/dynamic/genContentDestroyChildren.html
+/sdcard/android/layout_tests/fast/dynamic/floating-to-positioned.html
+/sdcard/android/layout_tests/fast/dynamic/floating-to-positioned-2.html
+/sdcard/android/layout_tests/fast/dynamic/float-withdrawal.html
+/sdcard/android/layout_tests/fast/dynamic/float-withdrawal-2.html
+/sdcard/android/layout_tests/fast/dynamic/float-no-longer-overhanging.html
+/sdcard/android/layout_tests/fast/dynamic/float-in-trailing-whitespace-after-last-line-break.html
+/sdcard/android/layout_tests/fast/dynamic/flash-replacement-test.html
+/sdcard/android/layout_tests/fast/dynamic/create-renderer-for-whitespace-only-text.html
+/sdcard/android/layout_tests/fast/dynamic/containing-block-change.html
+/sdcard/android/layout_tests/fast/dynamic/anonymous-block-orphaned-lines.html
+/sdcard/android/layout_tests/fast/dynamic/anonymous-block-layer-lost.html
+/sdcard/android/layout_tests/fast/dynamic/015.html
+/sdcard/android/layout_tests/fast/dynamic/014.html
+/sdcard/android/layout_tests/fast/dynamic/013.html
+/sdcard/android/layout_tests/fast/dynamic/012.html
+/sdcard/android/layout_tests/fast/dynamic/011.html
+/sdcard/android/layout_tests/fast/dynamic/010.html
+/sdcard/android/layout_tests/fast/dynamic/009.html
+/sdcard/android/layout_tests/fast/dynamic/008.html
+/sdcard/android/layout_tests/fast/dynamic/007.html
+/sdcard/android/layout_tests/fast/dynamic/006.html
+/sdcard/android/layout_tests/fast/dynamic/005.html
+/sdcard/android/layout_tests/fast/dynamic/004.html
+/sdcard/android/layout_tests/fast/dynamic/002.html
+/sdcard/android/layout_tests/fast/dynamic/001.html
+/sdcard/android/layout_tests/fast/dom/Window/open-existing-pop-up-blocking.html
+/sdcard/android/layout_tests/fast/dom/Window/btoa-pnglet.html
+/sdcard/android/layout_tests/fast/dom/Range/surroundContents-1.html
+/sdcard/android/layout_tests/fast/dom/Range/create-contextual-fragment.html
+/sdcard/android/layout_tests/fast/dom/HTMLTextAreaElement/reset-textarea.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/createCaption.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/colSpan.html
+/sdcard/android/layout_tests/fast/dom/HTMLStyleElement/insert-parser-generated.html
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/vspace-hspace-as-number.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead5.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead4.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead3.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead2.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead1.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/head-link-style-href-check.html
+/sdcard/android/layout_tests/fast/dom/HTMLElement/bdo.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/frameless-location-bugzilla10837.html
+/sdcard/android/layout_tests/fast/dom/Element/null-offset-parent.html
+/sdcard/android/layout_tests/fast/dom/Document/early-document-access.html
+/sdcard/android/layout_tests/fast/dom/row-inner-text.html
+/sdcard/android/layout_tests/fast/dom/replaceChild.html
+/sdcard/android/layout_tests/fast/dom/outerText.html
+/sdcard/android/layout_tests/fast/dom/isindex-002.html
+/sdcard/android/layout_tests/fast/dom/isindex-001.html
+/sdcard/android/layout_tests/fast/dom/focus-contenteditable.html
+/sdcard/android/layout_tests/fast/dom/dom-parse-serialize-display.html
+/sdcard/android/layout_tests/fast/dom/delete-contents.html
+/sdcard/android/layout_tests/fast/dom/css-rule-functions.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-insertRule-update.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-deleteRule-update.html
+/sdcard/android/layout_tests/fast/dom/css-inline-style-important.html
+/sdcard/android/layout_tests/fast/dom/css-cached-import-rule.html
+/sdcard/android/layout_tests/fast/dom/clone-node-dynamic-style.html
+/sdcard/android/layout_tests/fast/dom/clone-contents-0-end-offset.html
+/sdcard/android/layout_tests/fast/dom/clientWidthAfterDocumentIsRemoved.html
+/sdcard/android/layout_tests/fast/dom/children-nodes.html
+/sdcard/android/layout_tests/fast/dom/blur-contenteditable.html
+/sdcard/android/layout_tests/fast/dom/attr_dead_doc.html
+/sdcard/android/layout_tests/fast/doctypes/004.html
+/sdcard/android/layout_tests/fast/doctypes/003.html
+/sdcard/android/layout_tests/fast/doctypes/002.html
+/sdcard/android/layout_tests/fast/doctypes/001.html
+/sdcard/android/layout_tests/fast/css-generated-content/wbr-with-before-content.html
+/sdcard/android/layout_tests/fast/css-generated-content/visibleContentHiddenParent.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-group-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-group-to-inline.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-cell-before-content.html
+/sdcard/android/layout_tests/fast/css-generated-content/spellingToolTip-assert.html
+/sdcard/android/layout_tests/fast/css-generated-content/positioned-background-hit-test-crash.html
+/sdcard/android/layout_tests/fast/css-generated-content/no-openclose-quote.html
+/sdcard/android/layout_tests/fast/css-generated-content/inline-display-types.html
+/sdcard/android/layout_tests/fast/css-generated-content/hover-style-change.html
+/sdcard/android/layout_tests/fast/css-generated-content/before-with-first-letter.html
+/sdcard/android/layout_tests/fast/css-generated-content/after-order.html
+/sdcard/android/layout_tests/fast/css-generated-content/absolute-position-inside-inline.html
+/sdcard/android/layout_tests/fast/css-generated-content/016.html
+/sdcard/android/layout_tests/fast/css-generated-content/015.html
+/sdcard/android/layout_tests/fast/css-generated-content/014.html
+/sdcard/android/layout_tests/fast/css-generated-content/013.html
+/sdcard/android/layout_tests/fast/css-generated-content/012.html
+/sdcard/android/layout_tests/fast/css-generated-content/011.html
+/sdcard/android/layout_tests/fast/css-generated-content/010.html
+/sdcard/android/layout_tests/fast/css-generated-content/009.html
+/sdcard/android/layout_tests/fast/css-generated-content/008.html
+/sdcard/android/layout_tests/fast/css-generated-content/007.html
+/sdcard/android/layout_tests/fast/css-generated-content/005.html
+/sdcard/android/layout_tests/fast/css-generated-content/004.html
+/sdcard/android/layout_tests/fast/css-generated-content/003.html
+/sdcard/android/layout_tests/fast/css-generated-content/002.html
+/sdcard/android/layout_tests/fast/css-generated-content/001.html
+/sdcard/android/layout_tests/fast/css/variables/variable-iteration-test.html
+/sdcard/android/layout_tests/fast/css/variables/shorthand-test.html
+/sdcard/android/layout_tests/fast/css/variables/set-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/remove-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/print-test.html
+/sdcard/android/layout_tests/fast/css/variables/override-test.html
+/sdcard/android/layout_tests/fast/css/variables/multiple-term-test.html
+/sdcard/android/layout_tests/fast/css/variables/multiple-blocks-test.html
+/sdcard/android/layout_tests/fast/css/variables/misplaced-variables-test.html
+/sdcard/android/layout_tests/fast/css/variables/misplaced-import-test.html
+/sdcard/android/layout_tests/fast/css/variables/margin-test.html
+/sdcard/android/layout_tests/fast/css/variables/invalid-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/inline-style-test.html
+/sdcard/android/layout_tests/fast/css/variables/import-test.html
+/sdcard/android/layout_tests/fast/css/variables/image-test.html
+/sdcard/android/layout_tests/fast/css/variables/font-test.html
+/sdcard/android/layout_tests/fast/css/variables/declaration-block-test.html
+/sdcard/android/layout_tests/fast/css/variables/colors-test.html
+/sdcard/android/layout_tests/fast/css/variables/block-cycle-test.html
+/sdcard/android/layout_tests/fast/css/namespaces/007.xml
+/sdcard/android/layout_tests/fast/css/namespaces/006.xml
+/sdcard/android/layout_tests/fast/css/namespaces/005.xml
+/sdcard/android/layout_tests/fast/css/namespaces/004.xml
+/sdcard/android/layout_tests/fast/css/namespaces/003.xml
+/sdcard/android/layout_tests/fast/css/namespaces/002.xml
+/sdcard/android/layout_tests/fast/css/namespaces/001.xml
+/sdcard/android/layout_tests/fast/css/counters/invalidate-cached-counter-node.html
+/sdcard/android/layout_tests/fast/css/counters/counter-text-transform.html
+/sdcard/android/layout_tests/fast/css/counters/counter-text-security.html
+/sdcard/android/layout_tests/fast/css/zoom-property-parsing.html
+/sdcard/android/layout_tests/fast/css/zoom-font-size.html
+/sdcard/android/layout_tests/fast/css/ZeroOpacityLayers2.html
+/sdcard/android/layout_tests/fast/css/ZeroOpacityLayers.html
+/sdcard/android/layout_tests/fast/css/xml-stylesheet-pi-not-in-prolog.xml
+/sdcard/android/layout_tests/fast/css/word-space-extra.html
+/sdcard/android/layout_tests/fast/css/visibility-hit-test.html
+/sdcard/android/layout_tests/fast/css/vertical-align-lengths.html
+/sdcard/android/layout_tests/fast/css/value-list-out-of-bounds-crash.html
+/sdcard/android/layout_tests/fast/css/universal-hover-quirk.html
+/sdcard/android/layout_tests/fast/css/transition-color-unspecified.html
+/sdcard/android/layout_tests/fast/css/transform-default-parameter.html
+/sdcard/android/layout_tests/fast/css/textCapitalizeEdgeCases.html
+/sdcard/android/layout_tests/fast/css/text-security.html
+/sdcard/android/layout_tests/fast/css/text-align.html
+/sdcard/android/layout_tests/fast/css/target-fragment-match.html
+/sdcard/android/layout_tests/fast/css/table-text-align-strict.html
+/sdcard/android/layout_tests/fast/css/table-text-align-quirk.html
+/sdcard/android/layout_tests/fast/css/style-parsed-outside-head.html
+/sdcard/android/layout_tests/fast/css/style-outside-head.html
+/sdcard/android/layout_tests/fast/css/simple-selector-chain-parsing.html
+/sdcard/android/layout_tests/fast/css/shadow-multiple.html
+/sdcard/android/layout_tests/fast/css/selector-set-attribute.html
+/sdcard/android/layout_tests/fast/css/rtl-ordering.html
+/sdcard/android/layout_tests/fast/css/rgb-float.html
+/sdcard/android/layout_tests/fast/css/resize-corner-tracking.html
+/sdcard/android/layout_tests/fast/css/quirk-orphaned-units.html
+/sdcard/android/layout_tests/fast/css/position-negative-top-margin.html
+/sdcard/android/layout_tests/fast/css/percentage-non-integer.html
+/sdcard/android/layout_tests/fast/css/pendingStylesheetFontSize.html
+/sdcard/android/layout_tests/fast/css/outline-auto-location.html
+/sdcard/android/layout_tests/fast/css/outline-auto-empty-rects.html
+/sdcard/android/layout_tests/fast/css/only-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/only-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/negative-nth-child.html
+/sdcard/android/layout_tests/fast/css/max-height-none.html
+/sdcard/android/layout_tests/fast/css/MarqueeLayoutTest.html
+/sdcard/android/layout_tests/fast/css/marginComputedStyle.html
+/sdcard/android/layout_tests/fast/css/margin-top-bottom-dynamic.html
+/sdcard/android/layout_tests/fast/css/margin-bottom-form-element-strict.html
+/sdcard/android/layout_tests/fast/css/margin-bottom-form-element-quirk.html
+/sdcard/android/layout_tests/fast/css/live-cssrules.html
+/sdcard/android/layout_tests/fast/css/list-outline.html
+/sdcard/android/layout_tests/fast/css/link-outside-head.html
+/sdcard/android/layout_tests/fast/css/line-height.html
+/sdcard/android/layout_tests/fast/css/line-height-overflow.html
+/sdcard/android/layout_tests/fast/css/line-height-negative.html
+/sdcard/android/layout_tests/fast/css/line-height-font-order.html
+/sdcard/android/layout_tests/fast/css/layerZOrderCrash.html
+/sdcard/android/layout_tests/fast/css/last-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/last-child-style-sharing.html
+/sdcard/android/layout_tests/fast/css/last-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors-3.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors-2.html
+/sdcard/android/layout_tests/fast/css/invalid-pseudo-classes.html
+/sdcard/android/layout_tests/fast/css/invalid-percentage-property.html
+/sdcard/android/layout_tests/fast/css/inline-properties-important.html
+/sdcard/android/layout_tests/fast/css/import_with_baseurl.html
+/sdcard/android/layout_tests/fast/css/import-rule-regression-11590.html
+/sdcard/android/layout_tests/fast/css/imageTileOpacity.html
+/sdcard/android/layout_tests/fast/css/ignore-text-zoom.html
+/sdcard/android/layout_tests/fast/css/hsla-color.html
+/sdcard/android/layout_tests/fast/css/hsl-color.html
+/sdcard/android/layout_tests/fast/css/hover-subselector.html
+/sdcard/android/layout_tests/fast/css/font_property_normal.html
+/sdcard/android/layout_tests/fast/css/font-weight-1.html
+/sdcard/android/layout_tests/fast/css/font-size-negative.html
+/sdcard/android/layout_tests/fast/css/font-shorthand-weight-only.html
+/sdcard/android/layout_tests/fast/css/font-face-unicode-range.html
+/sdcard/android/layout_tests/fast/css/font-face-remote.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-remote-sources.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-faces.html
+/sdcard/android/layout_tests/fast/css/font-face-descriptor-multiple-values.html
+/sdcard/android/layout_tests/fast/css/font-face-in-media-rule.html
+/sdcard/android/layout_tests/fast/css/font-face-default-font.html
+/sdcard/android/layout_tests/fast/css/first-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/first-letter-visibility.html
+/sdcard/android/layout_tests/fast/css/first-letter-skip-out-of-flow.html
+/sdcard/android/layout_tests/fast/css/first-letter-recalculation.html
+/sdcard/android/layout_tests/fast/css/first-letter-hover.html
+/sdcard/android/layout_tests/fast/css/first-letter-float.html
+/sdcard/android/layout_tests/fast/css/first-letter-float-after-float.html
+/sdcard/android/layout_tests/fast/css/first-letter-detach.html
+/sdcard/android/layout_tests/fast/css/first-letter-capitalized.html
+/sdcard/android/layout_tests/fast/css/first-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/find-next-layer.html
+/sdcard/android/layout_tests/fast/css/fieldset-display-row.html
+/sdcard/android/layout_tests/fast/css/ex-after-font-variant.html
+/sdcard/android/layout_tests/fast/css/error-in-last-decl.html
+/sdcard/android/layout_tests/fast/css/empty-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/empty-generated-content.html
+/sdcard/android/layout_tests/fast/css/empty-body-test.html
+/sdcard/android/layout_tests/fast/css/dynamic-sibling-selector.html
+/sdcard/android/layout_tests/fast/css/disabled-author-styles.html
+/sdcard/android/layout_tests/fast/css/css3-nth-child.html
+/sdcard/android/layout_tests/fast/css/css3-modsel-22.html
+/sdcard/android/layout_tests/fast/css/css2-system-fonts.html
+/sdcard/android/layout_tests/fast/css/css-imports.html
+/sdcard/android/layout_tests/fast/css/continuationCrash.html
+/sdcard/android/layout_tests/fast/css/contentImage.html
+/sdcard/android/layout_tests/fast/css/contentDivWithChildren.html
+/sdcard/android/layout_tests/fast/css/contentDiv.html
+/sdcard/android/layout_tests/fast/css/content-dynamic.html
+/sdcard/android/layout_tests/fast/css/color-quirk.html
+/sdcard/android/layout_tests/fast/css/border-height.html
+/sdcard/android/layout_tests/fast/css/begin-end-contain-selector-empty-value.html
+/sdcard/android/layout_tests/fast/css/background-shorthand-invalid-url.html
+/sdcard/android/layout_tests/fast/css/background-image-with-baseurl.html
+/sdcard/android/layout_tests/fast/css/attribute-selector-empty-value.html
+/sdcard/android/layout_tests/fast/css/apple-prefix.html
+/sdcard/android/layout_tests/fast/css/affected-by-hover-after-style-change.html
+/sdcard/android/layout_tests/fast/css/acid2.html
+/sdcard/android/layout_tests/fast/css/acid2-pixel.html
+/sdcard/android/layout_tests/fast/css/absolute-poition-in-rtl-parent.html
+/sdcard/android/layout_tests/fast/css/008.html
+/sdcard/android/layout_tests/fast/css/007.html
+/sdcard/android/layout_tests/fast/css/006.html
+/sdcard/android/layout_tests/fast/css/005.html
+/sdcard/android/layout_tests/fast/css/004.html
+/sdcard/android/layout_tests/fast/css/003.html
+/sdcard/android/layout_tests/fast/css/002.html
+/sdcard/android/layout_tests/fast/css/001.html
+/sdcard/android/layout_tests/fast/compact/003.html
+/sdcard/android/layout_tests/fast/compact/002.html
+/sdcard/android/layout_tests/fast/compact/001.html
+/sdcard/android/layout_tests/fast/clip/outline-overflowClip.html
+/sdcard/android/layout_tests/fast/clip/nestedTransparencyClip.html
+/sdcard/android/layout_tests/fast/clip/017.html
+/sdcard/android/layout_tests/fast/clip/016.html
+/sdcard/android/layout_tests/fast/clip/015.html
+/sdcard/android/layout_tests/fast/clip/014.html
+/sdcard/android/layout_tests/fast/clip/013.html
+/sdcard/android/layout_tests/fast/clip/012.html
+/sdcard/android/layout_tests/fast/clip/011.html
+/sdcard/android/layout_tests/fast/clip/010.html
+/sdcard/android/layout_tests/fast/clip/009.html
+/sdcard/android/layout_tests/fast/clip/008.html
+/sdcard/android/layout_tests/fast/clip/007.html
+/sdcard/android/layout_tests/fast/clip/006.html
+/sdcard/android/layout_tests/fast/clip/005.html
+/sdcard/android/layout_tests/fast/clip/004.html
+/sdcard/android/layout_tests/fast/clip/003.html
+/sdcard/android/layout_tests/fast/clip/002.html
+/sdcard/android/layout_tests/fast/clip/001.html
+/sdcard/android/layout_tests/fast/canvas/zero-size-fill-rect.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-7.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-6.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-5.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-4.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-3.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-2.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-1.html
+/sdcard/android/layout_tests/fast/canvas/quadraticCurveTo.xml
+/sdcard/android/layout_tests/fast/canvas/patternfill-repeat.html
+/sdcard/android/layout_tests/fast/canvas/image-object-in-canvas.html
+/sdcard/android/layout_tests/fast/canvas/gradient-empty-path.html
+/sdcard/android/layout_tests/fast/canvas/fillrect_gradient.html
+/sdcard/android/layout_tests/fast/canvas/fillrect-gradient-zero-stops.html
+/sdcard/android/layout_tests/fast/canvas/fill-stroke-clip-reset-path.html
+/sdcard/android/layout_tests/fast/canvas/drawImage.html
+/sdcard/android/layout_tests/fast/canvas/canvasDrawingIntoSelf.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transforms-during-path.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-skewed.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-non-invertible.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-nan.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-multiply.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-infinity.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-identity.html
+/sdcard/android/layout_tests/fast/canvas/canvas-text-baseline.html
+/sdcard/android/layout_tests/fast/canvas/canvas-text-alignment.html
+/sdcard/android/layout_tests/fast/canvas/canvas-size-change-after-layout.html
+/sdcard/android/layout_tests/fast/canvas/canvas-resize-reset.html
+/sdcard/android/layout_tests/fast/canvas/canvas-bg.html
+/sdcard/android/layout_tests/fast/canvas/canvas-before-css.html
+/sdcard/android/layout_tests/fast/box-sizing/panels-two.html
+/sdcard/android/layout_tests/fast/box-sizing/panels-one.html
+/sdcard/android/layout_tests/fast/box-sizing/box-sizing.html
+/sdcard/android/layout_tests/fast/box-shadow/border-radius-big.html
+/sdcard/android/layout_tests/fast/box-shadow/basic-shadows.html
+/sdcard/android/layout_tests/fast/borders/svg-as-border-image.html
+/sdcard/android/layout_tests/fast/borders/svg-as-border-image-2.html
+/sdcard/android/layout_tests/fast/borders/outline-offset-min-assert.html
+/sdcard/android/layout_tests/fast/borders/inline-mask-overlay-image.html
+/sdcard/android/layout_tests/fast/borders/fieldsetBorderRadius.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid04.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusRidge01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusOutset01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusInvalidColor.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusInset01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusGroove02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusGroove01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusArcs01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusAllStylesAllCorners.html
+/sdcard/android/layout_tests/fast/borders/border-radius-huge-assert.html
+/sdcard/android/layout_tests/fast/borders/border-image-scale-transform.html
+/sdcard/android/layout_tests/fast/borders/border-image-rotate-transform.html
+/sdcard/android/layout_tests/fast/borders/border-image-omit-right-slice.html
+/sdcard/android/layout_tests/fast/borders/border-image-01.html
+/sdcard/android/layout_tests/fast/borders/border-fit.html
+/sdcard/android/layout_tests/fast/borders/border-color-inherit.html
+/sdcard/android/layout_tests/fast/borders/block-mask-overlay-image.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/007.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/006.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/005.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/004.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/003.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/002.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/001.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/010.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/009.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/008.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/007.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/006.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/005.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/004.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/003.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/002.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/001.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/008.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/007.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/006.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/005.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/004.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/003.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/002.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/001.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/007.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/006.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/005.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/004.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/003.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/002.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/001.html
+/sdcard/android/layout_tests/fast/block/positioning/window-height-change.html
+/sdcard/android/layout_tests/fast/block/positioning/replaced-inside-fixed-top-bottom.html
+/sdcard/android/layout_tests/fast/block/positioning/relayout-on-position-change.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-replaced.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-replaced-float.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-block.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overconstrained.html
+/sdcard/android/layout_tests/fast/block/positioning/pref-width-change.html
+/sdcard/android/layout_tests/fast/block/positioning/padding-percent.html
+/sdcard/android/layout_tests/fast/block/positioning/offsetLeft-offsetTop-borders.html
+/sdcard/android/layout_tests/fast/block/positioning/negative-right-pos.html
+/sdcard/android/layout_tests/fast/block/positioning/move-with-auto-width.html
+/sdcard/android/layout_tests/fast/block/positioning/leftmargin-topmargin.html
+/sdcard/android/layout_tests/fast/block/positioning/inline-block-relposition.html
+/sdcard/android/layout_tests/fast/block/positioning/height-change.html
+/sdcard/android/layout_tests/fast/block/positioning/complex-percentage-height.html
+/sdcard/android/layout_tests/fast/block/positioning/child-of-absolute-with-auto-height.html
+/sdcard/android/layout_tests/fast/block/positioning/auto-height-with-top-and-bottom.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-with-html-border-strict.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-with-html-border-quirks.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-positioned-overconstrained.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-position-direction-strict.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-position-direction-quirk.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-length-of-neg-666666.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-short-rtl.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-short-ltr.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-3.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-2.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr-3.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr-2.html
+/sdcard/android/layout_tests/fast/block/positioning/abs-inside-inline-rel.html
+/sdcard/android/layout_tests/fast/block/positioning/062.html
+/sdcard/android/layout_tests/fast/block/positioning/061.html
+/sdcard/android/layout_tests/fast/block/positioning/060.html
+/sdcard/android/layout_tests/fast/block/positioning/059.html
+/sdcard/android/layout_tests/fast/block/positioning/058.html
+/sdcard/android/layout_tests/fast/block/positioning/057.html
+/sdcard/android/layout_tests/fast/block/positioning/056.html
+/sdcard/android/layout_tests/fast/block/positioning/055.html
+/sdcard/android/layout_tests/fast/block/positioning/054.html
+/sdcard/android/layout_tests/fast/block/positioning/053.html
+/sdcard/android/layout_tests/fast/block/positioning/052.html
+/sdcard/android/layout_tests/fast/block/positioning/051.html
+/sdcard/android/layout_tests/fast/block/positioning/050.html
+/sdcard/android/layout_tests/fast/block/positioning/049.html
+/sdcard/android/layout_tests/fast/block/positioning/048.html
+/sdcard/android/layout_tests/fast/block/positioning/047.html
+/sdcard/android/layout_tests/fast/block/positioning/046.html
+/sdcard/android/layout_tests/fast/block/positioning/045.html
+/sdcard/android/layout_tests/fast/block/positioning/044.html
+/sdcard/android/layout_tests/fast/block/positioning/043.html
+/sdcard/android/layout_tests/fast/block/positioning/042.html
+/sdcard/android/layout_tests/fast/block/positioning/041.html
+/sdcard/android/layout_tests/fast/block/positioning/040.html
+/sdcard/android/layout_tests/fast/block/positioning/039.html
+/sdcard/android/layout_tests/fast/block/positioning/038.html
+/sdcard/android/layout_tests/fast/block/positioning/037.html
+/sdcard/android/layout_tests/fast/block/positioning/036.html
+/sdcard/android/layout_tests/fast/block/positioning/035.html
+/sdcard/android/layout_tests/fast/block/positioning/034.html
+/sdcard/android/layout_tests/fast/block/positioning/033.html
+/sdcard/android/layout_tests/fast/block/positioning/032.html
+/sdcard/android/layout_tests/fast/block/positioning/031.html
+/sdcard/android/layout_tests/fast/block/positioning/030.html
+/sdcard/android/layout_tests/fast/block/positioning/029.html
+/sdcard/android/layout_tests/fast/block/positioning/028.html
+/sdcard/android/layout_tests/fast/block/positioning/027.html
+/sdcard/android/layout_tests/fast/block/positioning/026.html
+/sdcard/android/layout_tests/fast/block/positioning/025.html
+/sdcard/android/layout_tests/fast/block/positioning/024.html
+/sdcard/android/layout_tests/fast/block/positioning/023.html
+/sdcard/android/layout_tests/fast/block/positioning/022.html
+/sdcard/android/layout_tests/fast/block/positioning/021.html
+/sdcard/android/layout_tests/fast/block/positioning/020.html
+/sdcard/android/layout_tests/fast/block/positioning/019.html
+/sdcard/android/layout_tests/fast/block/positioning/018.html
+/sdcard/android/layout_tests/fast/block/positioning/017.html
+/sdcard/android/layout_tests/fast/block/positioning/016.html
+/sdcard/android/layout_tests/fast/block/positioning/015.html
+/sdcard/android/layout_tests/fast/block/positioning/014.html
+/sdcard/android/layout_tests/fast/block/positioning/013.html
+/sdcard/android/layout_tests/fast/block/positioning/012.html
+/sdcard/android/layout_tests/fast/block/positioning/011.html
+/sdcard/android/layout_tests/fast/block/positioning/010.html
+/sdcard/android/layout_tests/fast/block/positioning/009.html
+/sdcard/android/layout_tests/fast/block/positioning/008.html
+/sdcard/android/layout_tests/fast/block/positioning/007.html
+/sdcard/android/layout_tests/fast/block/positioning/006.html
+/sdcard/android/layout_tests/fast/block/positioning/005.html
+/sdcard/android/layout_tests/fast/block/positioning/004.html
+/sdcard/android/layout_tests/fast/block/positioning/003.html
+/sdcard/android/layout_tests/fast/block/positioning/002.html
+/sdcard/android/layout_tests/fast/block/positioning/001.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/negative-margins.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/empty-clear-blocks.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/104.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/103.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/102.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/101.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/100.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/063.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/062.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/059.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/058.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/057.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/056.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/055.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/045.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/044.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/043.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/042.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/041.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/040.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/039.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/038.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/037.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/035.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/034.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/033.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/032.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/031.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/030.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/029.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/028.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/027.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/026.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/025.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/022.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/021.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/020.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/019.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/018.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/017.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/016.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/015.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/012.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/011.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/010.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/006.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/005.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/004.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/003.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/002.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/001.html
+/sdcard/android/layout_tests/fast/block/float/width-update-after-clear.html
+/sdcard/android/layout_tests/fast/block/float/vertical-move-relayout.html
+/sdcard/android/layout_tests/fast/block/float/tableshifting.html
+/sdcard/android/layout_tests/fast/block/float/table-relayout.html
+/sdcard/android/layout_tests/fast/block/float/shrink-to-fit-width.html
+/sdcard/android/layout_tests/fast/block/float/relative-painted-twice.html
+/sdcard/android/layout_tests/fast/block/float/overhanging-after-height-decrease.html
+/sdcard/android/layout_tests/fast/block/float/overhanging-after-height-decrease-offsets.html
+/sdcard/android/layout_tests/fast/block/float/nowrap-clear-min-width.html
+/sdcard/android/layout_tests/fast/block/float/nopaint-after-layer-destruction2.html
+/sdcard/android/layout_tests/fast/block/float/nopaint-after-layer-destruction.html
+/sdcard/android/layout_tests/fast/block/float/nestedAnonymousBlocks2.html
+/sdcard/android/layout_tests/fast/block/float/nestedAnonymousBlocks.html
+/sdcard/android/layout_tests/fast/block/float/negative-margin-clear.html
+/sdcard/android/layout_tests/fast/block/float/narrow-after-wide.html
+/sdcard/android/layout_tests/fast/block/float/multiple-float-positioning.html
+/sdcard/android/layout_tests/fast/block/float/marquee-shrink-to-avoid-floats.html
+/sdcard/android/layout_tests/fast/block/float/intruding-painted-twice.html
+/sdcard/android/layout_tests/fast/block/float/independent-align-positioning.html
+/sdcard/android/layout_tests/fast/block/float/float-on-zero-height-line.html
+/sdcard/android/layout_tests/fast/block/float/float-in-float-painting.html
+/sdcard/android/layout_tests/fast/block/float/float-in-float-hit-testing.html
+/sdcard/android/layout_tests/fast/block/float/float-avoidance.html
+/sdcard/android/layout_tests/fast/block/float/editable-text-overlapping-float.html
+/sdcard/android/layout_tests/fast/block/float/dynamic-unfloat-pref-width.html
+/sdcard/android/layout_tests/fast/block/float/clamped-right-float.html
+/sdcard/android/layout_tests/fast/block/float/br-with-clear.html
+/sdcard/android/layout_tests/fast/block/float/br-with-clear-2.html
+/sdcard/android/layout_tests/fast/block/float/4145535Crash.html
+/sdcard/android/layout_tests/fast/block/float/035.html
+/sdcard/android/layout_tests/fast/block/float/034.html
+/sdcard/android/layout_tests/fast/block/float/033.html
+/sdcard/android/layout_tests/fast/block/float/032.html
+/sdcard/android/layout_tests/fast/block/float/031.html
+/sdcard/android/layout_tests/fast/block/float/030.html
+/sdcard/android/layout_tests/fast/block/float/029.html
+/sdcard/android/layout_tests/fast/block/float/028.html
+/sdcard/android/layout_tests/fast/block/float/027.html
+/sdcard/android/layout_tests/fast/block/float/026.html
+/sdcard/android/layout_tests/fast/block/float/025.html
+/sdcard/android/layout_tests/fast/block/float/024.html
+/sdcard/android/layout_tests/fast/block/float/023.html
+/sdcard/android/layout_tests/fast/block/float/022.html
+/sdcard/android/layout_tests/fast/block/float/021.html
+/sdcard/android/layout_tests/fast/block/float/020.html
+/sdcard/android/layout_tests/fast/block/float/019.html
+/sdcard/android/layout_tests/fast/block/float/018.html
+/sdcard/android/layout_tests/fast/block/float/017.html
+/sdcard/android/layout_tests/fast/block/float/016.html
+/sdcard/android/layout_tests/fast/block/float/015.html
+/sdcard/android/layout_tests/fast/block/float/014.html
+/sdcard/android/layout_tests/fast/block/float/013.html
+/sdcard/android/layout_tests/fast/block/float/012.html
+/sdcard/android/layout_tests/fast/block/float/011.html
+/sdcard/android/layout_tests/fast/block/float/010.html
+/sdcard/android/layout_tests/fast/block/float/009.html
+/sdcard/android/layout_tests/fast/block/float/008.html
+/sdcard/android/layout_tests/fast/block/float/007.html
+/sdcard/android/layout_tests/fast/block/float/006.html
+/sdcard/android/layout_tests/fast/block/float/005.html
+/sdcard/android/layout_tests/fast/block/float/004.html
+/sdcard/android/layout_tests/fast/block/float/003.html
+/sdcard/android/layout_tests/fast/block/float/002.html
+/sdcard/android/layout_tests/fast/block/float/001.html
+/sdcard/android/layout_tests/fast/block/basic/white-space-pre-wraps.html
+/sdcard/android/layout_tests/fast/block/basic/text-indent-rtl.html
+/sdcard/android/layout_tests/fast/block/basic/quirk-percent-height-grandchild.html
+/sdcard/android/layout_tests/fast/block/basic/quirk-height.html
+/sdcard/android/layout_tests/fast/block/basic/minheight.html
+/sdcard/android/layout_tests/fast/block/basic/min-pref-width-nowrap-floats.html
+/sdcard/android/layout_tests/fast/block/basic/fieldset-stretch-to-legend.html
+/sdcard/android/layout_tests/fast/block/basic/adding-near-anonymous-block.html
+/sdcard/android/layout_tests/fast/block/basic/021.html
+/sdcard/android/layout_tests/fast/block/basic/020.html
+/sdcard/android/layout_tests/fast/block/basic/019.html
+/sdcard/android/layout_tests/fast/block/basic/018.html
+/sdcard/android/layout_tests/fast/block/basic/016.html
+/sdcard/android/layout_tests/fast/block/basic/015.html
+/sdcard/android/layout_tests/fast/block/basic/014.html
+/sdcard/android/layout_tests/fast/block/basic/013.html
+/sdcard/android/layout_tests/fast/block/basic/012.html
+/sdcard/android/layout_tests/fast/block/basic/011.html
+/sdcard/android/layout_tests/fast/block/basic/010.html
+/sdcard/android/layout_tests/fast/block/basic/009.html
+/sdcard/android/layout_tests/fast/block/basic/008.html
+/sdcard/android/layout_tests/fast/block/basic/007.html
+/sdcard/android/layout_tests/fast/block/basic/006.html
+/sdcard/android/layout_tests/fast/block/basic/005.html
+/sdcard/android/layout_tests/fast/block/basic/004.html
+/sdcard/android/layout_tests/fast/block/basic/003.html
+/sdcard/android/layout_tests/fast/block/basic/002.html
+/sdcard/android/layout_tests/fast/block/basic/001.html
+/sdcard/android/layout_tests/fast/backgrounds/size/zero.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize19.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize18.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize17.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize16.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize15.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize14.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize13.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize12.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize11.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize10.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize09.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize08.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize07.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize06.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize05.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize04.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize03.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize02.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize01.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/noRepeatCorrectClip.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/negative-offset-repeat.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/negative-offset-repeat-transformed.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/mask-negative-offset-repeat.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-mask.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-6.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-5.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-4.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-3.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-2.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-1.html
+/sdcard/android/layout_tests/fast/backgrounds/solid-color-context-restore.html
+/sdcard/android/layout_tests/fast/backgrounds/mask-composite.html
+/sdcard/android/layout_tests/fast/backgrounds/bgCompositeCopy.html
+/sdcard/android/layout_tests/fast/backgrounds/background-position-rounding.html
+/sdcard/android/layout_tests/fast/backgrounds/background-position-1.html
+/sdcard/android/layout_tests/fast/backgrounds/background-origin-root-element.html
+/sdcard/android/layout_tests/fast/backgrounds/background-inherit-color-bug.html
+/sdcard/android/layout_tests/fast/backgrounds/001.html
diff --git a/tests/DumpRenderTree/results/layout_tests_passed.txt b/tests/DumpRenderTree/results/layout_tests_passed.txt
new file mode 100644
index 0000000..03e920e
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_passed.txt
@@ -0,0 +1,990 @@
+/sdcard/android/layout_tests/fast/transforms/container-transform-crash.html
+/sdcard/android/layout_tests/fast/tokenizer/write-unclosed-script.html
+/sdcard/android/layout_tests/fast/tokenizer/write-partial-entity.html
+/sdcard/android/layout_tests/fast/tokenizer/write-inline-script-open.html
+/sdcard/android/layout_tests/fast/tokenizer/write-external-script-open.html
+/sdcard/android/layout_tests/fast/tokenizer/nested-multiple-scripts.html
+/sdcard/android/layout_tests/fast/tokenizer/nested-cached-scripts.html
+/sdcard/android/layout_tests/fast/tokenizer/lessthan-terminates-tags-and-attrs.html
+/sdcard/android/layout_tests/fast/tokenizer/image-empty-crash.html
+/sdcard/android/layout_tests/fast/tokenizer/ignore-tags-in-iframe.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-open.html
+/sdcard/android/layout_tests/fast/tokenizer/doctype-search-reset.html
+/sdcard/android/layout_tests/fast/tokenizer/badscript.html
+/sdcard/android/layout_tests/fast/tokenizer/ampersand-in-special-tag.html
+/sdcard/android/layout_tests/fast/tokenizer/004.html
+/sdcard/android/layout_tests/fast/text/line-breaks-after-ideographic-comma-or-full-stop.html
+/sdcard/android/layout_tests/fast/text/large-text-composed-char-dos.html
+/sdcard/android/layout_tests/fast/text/find-case-folding.html
+/sdcard/android/layout_tests/fast/table/td-display-nowrap.html
+/sdcard/android/layout_tests/fast/table/section-in-table-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/rowindex-comment-nodes.html
+/sdcard/android/layout_tests/fast/table/row-in-tbody-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/large-rowspan-crash.html
+/sdcard/android/layout_tests/fast/table/incomplete-table-in-fragment-hang.html
+/sdcard/android/layout_tests/fast/table/incomplete-table-in-fragment-2.html
+/sdcard/android/layout_tests/fast/table/form-in-tbody-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/form-in-table-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/form-in-row-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/empty-auto-column-zero-divide.html
+/sdcard/android/layout_tests/fast/table/destroy-cell-with-selection-crash.html
+/sdcard/android/layout_tests/fast/table/colgroup-relative.html
+/sdcard/android/layout_tests/fast/table/cell-in-row-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/border-changes.html
+/sdcard/android/layout_tests/fast/replaced/object-param-no-name.html
+/sdcard/android/layout_tests/fast/regex/test4.html
+/sdcard/android/layout_tests/fast/regex/test1.html
+/sdcard/android/layout_tests/fast/regex/slow.html
+/sdcard/android/layout_tests/fast/regex/early-acid3-86.html
+/sdcard/android/layout_tests/fast/reflections/teardown-crash.html
+/sdcard/android/layout_tests/fast/reflections/reflection-computed-style.html
+/sdcard/android/layout_tests/fast/parser/test-unicode-characters-in-attribute-name.html
+/sdcard/android/layout_tests/fast/parser/tag-with-exclamation-point.html
+/sdcard/android/layout_tests/fast/parser/strict-img-in-map.html
+/sdcard/android/layout_tests/fast/parser/script-after-frameset-assert.html
+/sdcard/android/layout_tests/fast/parser/rewrite-map.html
+/sdcard/android/layout_tests/fast/parser/rewrite-form.html
+/sdcard/android/layout_tests/fast/parser/residual-style-close-across-removed-block.html
+/sdcard/android/layout_tests/fast/parser/residual-style-close-across-n-blocks.html
+/sdcard/android/layout_tests/fast/parser/remove-parser-current-node.html
+/sdcard/android/layout_tests/fast/parser/remove-node-stack.html
+/sdcard/android/layout_tests/fast/parser/remove-current-node-parent.html
+/sdcard/android/layout_tests/fast/parser/pre-first-line-break.html
+/sdcard/android/layout_tests/fast/parser/parse-wbr.html
+/sdcard/android/layout_tests/fast/parser/p-in-scope.html
+/sdcard/android/layout_tests/fast/parser/p-in-scope-strict.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/number-sign-in-map-name.html
+/sdcard/android/layout_tests/fast/parser/nsup-entity.html
+/sdcard/android/layout_tests/fast/parser/input-textarea-inside-select-element.html
+/sdcard/android/layout_tests/fast/parser/html-whitespace.html
+/sdcard/android/layout_tests/fast/parser/hex-entities-length.html
+/sdcard/android/layout_tests/fast/parser/head-comment.html
+/sdcard/android/layout_tests/fast/parser/entity-surrogate-pairs.html
+/sdcard/android/layout_tests/fast/parser/entity-end-xmp-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-title-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-textarea-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-style-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-iframe-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-title.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/entities-in-html.html
+/sdcard/android/layout_tests/fast/parser/duplicate-html-body-element-IDs.html
+/sdcard/android/layout_tests/fast/parser/comment-in-title.html
+/sdcard/android/layout_tests/fast/parser/comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/assertion-empty-attribute.html
+/sdcard/android/layout_tests/fast/parser/area-in-div.html
+/sdcard/android/layout_tests/fast/overflow/onscroll-layer-self-destruct.html
+/sdcard/android/layout_tests/fast/overflow/generated-content-crash.html
+/sdcard/android/layout_tests/fast/multicol/gap-non-negative.html
+/sdcard/android/layout_tests/fast/multicol/content-height-zero-crash.html
+/sdcard/android/layout_tests/fast/loader/xmlhttprequest-bad-mimetype.html
+/sdcard/android/layout_tests/fast/loader/window-clearing.html
+/sdcard/android/layout_tests/fast/loader/user-style-sheet-resource-load-callbacks.html
+/sdcard/android/layout_tests/fast/loader/url-strip-cr-lf-tab.html
+/sdcard/android/layout_tests/fast/loader/url-parse-1.html
+/sdcard/android/layout_tests/fast/loader/url-data-replace-backslash.html
+/sdcard/android/layout_tests/fast/loader/unloadable-script.html
+/sdcard/android/layout_tests/fast/loader/simultaneous-reloads-assert.html
+/sdcard/android/layout_tests/fast/loader/redirect-with-open-subframe.html
+/sdcard/android/layout_tests/fast/loader/redirect-with-open-subframe-2.html
+/sdcard/android/layout_tests/fast/loader/meta-refresh-vs-open.html
+/sdcard/android/layout_tests/fast/loader/local-css-allowed-in-strict-mode.html
+/sdcard/android/layout_tests/fast/loader/loadInProgress.html
+/sdcard/android/layout_tests/fast/loader/link-no-URL.html
+/sdcard/android/layout_tests/fast/loader/javascript-url-encoding.html
+/sdcard/android/layout_tests/fast/loader/invalid-charset-on-script-crashes-loader.html
+/sdcard/android/layout_tests/fast/loader/inherit-charset-to-empty-frame.html
+/sdcard/android/layout_tests/fast/loader/iframe-recursive-synchronous-load.html
+/sdcard/android/layout_tests/fast/loader/font-face-empty.html
+/sdcard/android/layout_tests/fast/loader/file-URL-with-port-number.html
+/sdcard/android/layout_tests/fast/loader/external-script-URL-location.html
+/sdcard/android/layout_tests/fast/loader/empty-ref-versus-no-ref.html
+/sdcard/android/layout_tests/fast/loader/early-load-cancel.html
+/sdcard/android/layout_tests/fast/loader/data-url-encoding-html.html
+/sdcard/android/layout_tests/fast/loader/charset-parse.html
+/sdcard/android/layout_tests/fast/leaks/002.html
+/sdcard/android/layout_tests/fast/leaks/001.html
+/sdcard/android/layout_tests/fast/layers/resize-layer-deletion-crash.html
+/sdcard/android/layout_tests/fast/layers/removed-by-scroll-handler.html
+/sdcard/android/layout_tests/fast/layers/generated-layer-scrollbar-crash.html
+/sdcard/android/layout_tests/fast/js/pic/rehash-poisons-structure.html
+/sdcard/android/layout_tests/fast/js/pic/get-set-proxy-object.html
+/sdcard/android/layout_tests/fast/js/pic/get-empty-string.html
+/sdcard/android/layout_tests/fast/js/pic/dictionary-prototype.html
+/sdcard/android/layout_tests/fast/js/pic/cached-single-entry-transition.html
+/sdcard/android/layout_tests/fast/js/pic/cached-prototype-setter.html
+/sdcard/android/layout_tests/fast/js/pic/cached-getter-setter.html
+/sdcard/android/layout_tests/fast/js/pic/cached-getter-dictionary-and-proto.html
+/sdcard/android/layout_tests/fast/js/pic/cached-deleted-properties.html
+/sdcard/android/layout_tests/fast/js/window-location-href-file-urls.html
+/sdcard/android/layout_tests/fast/js/while-expression-value.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-vardecl.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-parameters.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-arguments.html
+/sdcard/android/layout_tests/fast/js/vardecl-blocks-init.html
+/sdcard/android/layout_tests/fast/js/var-shadows-arg-crash.html
+/sdcard/android/layout_tests/fast/js/var-declarations.html
+/sdcard/android/layout_tests/fast/js/var-declarations-shadowing.html
+/sdcard/android/layout_tests/fast/js/unmatching-argument-count.html
+/sdcard/android/layout_tests/fast/js/unexpected-constant-crash.html
+/sdcard/android/layout_tests/fast/js/typeof-syntax.html
+/sdcard/android/layout_tests/fast/js/typeof-codegen-crash.html
+/sdcard/android/layout_tests/fast/js/toString-try-else.html
+/sdcard/android/layout_tests/fast/js/toString-prefix-postfix-preserve-parens.html
+/sdcard/android/layout_tests/fast/js/toString-overrides.html
+/sdcard/android/layout_tests/fast/js/toString-number-dot-expr.html
+/sdcard/android/layout_tests/fast/js/toString-for-var-decl.html
+/sdcard/android/layout_tests/fast/js/toString-exception.html
+/sdcard/android/layout_tests/fast/js/tostring-exception-in-property-access.html
+/sdcard/android/layout_tests/fast/js/toString-elision-trailing-comma.html
+/sdcard/android/layout_tests/fast/js/toString-dontEnum.html
+/sdcard/android/layout_tests/fast/js/throw-from-array-sort.html
+/sdcard/android/layout_tests/fast/js/this-non-object-proto.html
+/sdcard/android/layout_tests/fast/js/switch-behaviour.html
+/sdcard/android/layout_tests/fast/js/string_replace.html
+/sdcard/android/layout_tests/fast/js/string-substr.html
+/sdcard/android/layout_tests/fast/js/string-split-ignore-case.html
+/sdcard/android/layout_tests/fast/js/string-sort.html
+/sdcard/android/layout_tests/fast/js/string-slice-abnormal-values.html
+/sdcard/android/layout_tests/fast/js/string-replace-exception-crash.html
+/sdcard/android/layout_tests/fast/js/string-replace-3.html
+/sdcard/android/layout_tests/fast/js/string-replace-2.html
+/sdcard/android/layout_tests/fast/js/string-property-iteration.html
+/sdcard/android/layout_tests/fast/js/string-index-overflow.html
+/sdcard/android/layout_tests/fast/js/string-from-char-code.html
+/sdcard/android/layout_tests/fast/js/string-capitalization.html
+/sdcard/android/layout_tests/fast/js/static-scope-object.html
+/sdcard/android/layout_tests/fast/js/statement-list-register-crash.html
+/sdcard/android/layout_tests/fast/js/stack-unwinding.html
+/sdcard/android/layout_tests/fast/js/sparse-array.html
+/sdcard/android/layout_tests/fast/js/sort-stability.html
+/sdcard/android/layout_tests/fast/js/sort-randomly.html
+/sdcard/android/layout_tests/fast/js/sort-large-array.html
+/sdcard/android/layout_tests/fast/js/slash-lineterminator-parse.html
+/sdcard/android/layout_tests/fast/js/select-options-remove.html
+/sdcard/android/layout_tests/fast/js/select-options-remove-gc.html
+/sdcard/android/layout_tests/fast/js/select-options-add.html
+/sdcard/android/layout_tests/fast/js/resize-array-assign.html
+/sdcard/android/layout_tests/fast/js/reserved-words.html
+/sdcard/android/layout_tests/fast/js/removing-Cf-characters.html
+/sdcard/android/layout_tests/fast/js/rehash-assign.html
+/sdcard/android/layout_tests/fast/js/regexp-unicode-overflow.html
+/sdcard/android/layout_tests/fast/js/regexp-unicode-handling.html
+/sdcard/android/layout_tests/fast/js/regexp-stack-overflow.html
+/sdcard/android/layout_tests/fast/js/regexp-ranges-and-escaped-hyphens.html
+/sdcard/android/layout_tests/fast/js/regexp-range-out-of-order.html
+/sdcard/android/layout_tests/fast/js/regexp-overflow.html
+/sdcard/android/layout_tests/fast/js/regexp-non-character.html
+/sdcard/android/layout_tests/fast/js/regexp-non-capturing-groups.html
+/sdcard/android/layout_tests/fast/js/regexp-non-bmp.html
+/sdcard/android/layout_tests/fast/js/regexp-no-extensions.html
+/sdcard/android/layout_tests/fast/js/regexp-negative-special-characters.html
+/sdcard/android/layout_tests/fast/js/regexp-many-brackets.html
+/sdcard/android/layout_tests/fast/js/regexp-lastindex.html
+/sdcard/android/layout_tests/fast/js/regexp-find-first-asserted.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-more.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-match.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-crash.html
+/sdcard/android/layout_tests/fast/js/regexp-divequal.html
+/sdcard/android/layout_tests/fast/js/regexp-compile.html
+/sdcard/android/layout_tests/fast/js/regexp-compile-crash.html
+/sdcard/android/layout_tests/fast/js/regexp-char-insensitive.html
+/sdcard/android/layout_tests/fast/js/regexp-caching.html
+/sdcard/android/layout_tests/fast/js/reentrant-call-unwind.html
+/sdcard/android/layout_tests/fast/js/read-modify-eval.html
+/sdcard/android/layout_tests/fast/js/propertyIsEnumerable.html
+/sdcard/android/layout_tests/fast/js/property-getters-and-setters.html
+/sdcard/android/layout_tests/fast/js/primitive-method-this.html
+/sdcard/android/layout_tests/fast/js/pretty-print.html
+/sdcard/android/layout_tests/fast/js/prefix-syntax.html
+/sdcard/android/layout_tests/fast/js/postfix-syntax.html
+/sdcard/android/layout_tests/fast/js/parse-backslash-before-newline.html
+/sdcard/android/layout_tests/fast/js/order-of-operations.html
+/sdcard/android/layout_tests/fast/js/object-prototype-toLocaleString.html
+/sdcard/android/layout_tests/fast/js/object-prototype-constructor.html
+/sdcard/android/layout_tests/fast/js/object-extra-comma.html
+/sdcard/android/layout_tests/fast/js/numeric-conversion.html
+/sdcard/android/layout_tests/fast/js/number-toString.html
+/sdcard/android/layout_tests/fast/js/number-toprecision.html
+/sdcard/android/layout_tests/fast/js/number-tofixed.html
+/sdcard/android/layout_tests/fast/js/number-toExponential.html
+/sdcard/android/layout_tests/fast/js/null-char-in-string.html
+/sdcard/android/layout_tests/fast/js/non-object-proto.html
+/sdcard/android/layout_tests/fast/js/nested-function-scope.html
+/sdcard/android/layout_tests/fast/js/navigator-plugins-crash.html
+/sdcard/android/layout_tests/fast/js/named-function-expression.html
+/sdcard/android/layout_tests/fast/js/modify-non-references.html
+/sdcard/android/layout_tests/fast/js/mod-crash.html
+/sdcard/android/layout_tests/fast/js/missing-title-end-tag-js.html
+/sdcard/android/layout_tests/fast/js/math.html
+/sdcard/android/layout_tests/fast/js/logical-or-jless.html
+/sdcard/android/layout_tests/fast/js/lexical-lookup-in-function-constructor.html
+/sdcard/android/layout_tests/fast/js/lastModified.html
+/sdcard/android/layout_tests/fast/js/isPrototypeOf.html
+/sdcard/android/layout_tests/fast/js/invalid-syntax-for-function.html
+/sdcard/android/layout_tests/fast/js/integer-extremes.html
+/sdcard/android/layout_tests/fast/js/implicit-global-to-global-reentry.html
+/sdcard/android/layout_tests/fast/js/implicit-call-with-global-reentry.html
+/sdcard/android/layout_tests/fast/js/has-own-property.html
+/sdcard/android/layout_tests/fast/js/gmail-re-re.html
+/sdcard/android/layout_tests/fast/js/global-var-limit.html
+/sdcard/android/layout_tests/fast/js/getter-setter-gc.html
+/sdcard/android/layout_tests/fast/js/function-toString-parentheses.html
+/sdcard/android/layout_tests/fast/js/function-toString-object-literals.html
+/sdcard/android/layout_tests/fast/js/function-redefinition.html
+/sdcard/android/layout_tests/fast/js/function-prototype.html
+/sdcard/android/layout_tests/fast/js/function-names.html
+/sdcard/android/layout_tests/fast/js/function-name.html
+/sdcard/android/layout_tests/fast/js/function-dot-arguments.html
+/sdcard/android/layout_tests/fast/js/function-dot-arguments-and-caller.html
+/sdcard/android/layout_tests/fast/js/function-decompilation-operators.html
+/sdcard/android/layout_tests/fast/js/function-declarations.html
+/sdcard/android/layout_tests/fast/js/function-declarations-in-switch-statement.html
+/sdcard/android/layout_tests/fast/js/function-call-register-allocation.html
+/sdcard/android/layout_tests/fast/js/function-argument-evaluation-before-exception.html
+/sdcard/android/layout_tests/fast/js/function-apply.html
+/sdcard/android/layout_tests/fast/js/for-in-var-scope.html
+/sdcard/android/layout_tests/fast/js/for-in-to-text.html
+/sdcard/android/layout_tests/fast/js/for-in-exeception.html
+/sdcard/android/layout_tests/fast/js/for-in-avoid-duplicates.html
+/sdcard/android/layout_tests/fast/js/finally-codegen-failure.html
+/sdcard/android/layout_tests/fast/js/exec-state-marking.html
+/sdcard/android/layout_tests/fast/js/exception-try-finally-scope-error.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-new.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-function-with-lazy-activation.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-eval-inside-closure.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-equal.html
+/sdcard/android/layout_tests/fast/js/exception-linenums.html
+/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-2.html
+/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-1.html
+/sdcard/android/layout_tests/fast/js/exception-expression-offset.html
+/sdcard/android/layout_tests/fast/js/eval-var-decl.html
+/sdcard/android/layout_tests/fast/js/eval-overriding.html
+/sdcard/android/layout_tests/fast/js/eval-keyword-vs-function.html
+/sdcard/android/layout_tests/fast/js/eval-cross-window.html
+/sdcard/android/layout_tests/fast/js/eval-cache-crash.html
+/sdcard/android/layout_tests/fast/js/equality.html
+/sdcard/android/layout_tests/fast/js/encode-URI-test.html
+/sdcard/android/layout_tests/fast/js/duplicate-param-crash.html
+/sdcard/android/layout_tests/fast/js/dot-node-base-exception.html
+/sdcard/android/layout_tests/fast/js/do-while-without-semicolon.html
+/sdcard/android/layout_tests/fast/js/do-while-semicolon.html
+/sdcard/android/layout_tests/fast/js/do-while-expression-value.html
+/sdcard/android/layout_tests/fast/js/direct-entry-to-function-code.html
+/sdcard/android/layout_tests/fast/js/delete-then-put.html
+/sdcard/android/layout_tests/fast/js/delete-syntax.html
+/sdcard/android/layout_tests/fast/js/delete-multiple-global-blocks.html
+/sdcard/android/layout_tests/fast/js/delete-getters-setters.html
+/sdcard/android/layout_tests/fast/js/delete-function-parameter.html
+/sdcard/android/layout_tests/fast/js/deep-recursion-test.html
+/sdcard/android/layout_tests/fast/js/declaration-in-block.html
+/sdcard/android/layout_tests/fast/js/debugger.html
+/sdcard/android/layout_tests/fast/js/date-set-to-nan.html
+/sdcard/android/layout_tests/fast/js/date-proto-generic-invocation.html
+/sdcard/android/layout_tests/fast/js/date-preserve-milliseconds.html
+/sdcard/android/layout_tests/fast/js/date-parse-test.html
+/sdcard/android/layout_tests/fast/js/date-parse-comments-test.html
+/sdcard/android/layout_tests/fast/js/date-negative-setmonth.html
+/sdcard/android/layout_tests/fast/js/date-DST-time-cusps.html
+/sdcard/android/layout_tests/fast/js/date-DST-pre-1970.html
+/sdcard/android/layout_tests/fast/js/date-constructor.html
+/sdcard/android/layout_tests/fast/js/date-big-setmonth.html
+/sdcard/android/layout_tests/fast/js/date-big-setdate.html
+/sdcard/android/layout_tests/fast/js/date-big-constructor.html
+/sdcard/android/layout_tests/fast/js/cyclic-ref-toString.html
+/sdcard/android/layout_tests/fast/js/cyclic-prototypes.html
+/sdcard/android/layout_tests/fast/js/cyclic-proto.html
+/sdcard/android/layout_tests/fast/js/convert-nan-to-bool.html
+/sdcard/android/layout_tests/fast/js/continue-break-multiple-labels.html
+/sdcard/android/layout_tests/fast/js/constructor.html
+/sdcard/android/layout_tests/fast/js/constructor-attributes.html
+/sdcard/android/layout_tests/fast/js/construct-global-object.html
+/sdcard/android/layout_tests/fast/js/constant-folding.html
+/sdcard/android/layout_tests/fast/js/constant-count.html
+/sdcard/android/layout_tests/fast/js/const.html
+/sdcard/android/layout_tests/fast/js/const-without-initializer.html
+/sdcard/android/layout_tests/fast/js/comparefn-sort-stability.html
+/sdcard/android/layout_tests/fast/js/codegen-temporaries.html
+/sdcard/android/layout_tests/fast/js/codegen-temporaries-multiple-global-blocks.html
+/sdcard/android/layout_tests/fast/js/codegen-peephole-locals.html
+/sdcard/android/layout_tests/fast/js/codegen-loops-logical-nodes.html
+/sdcard/android/layout_tests/fast/js/code-serialize-paren.html
+/sdcard/android/layout_tests/fast/js/closure-inside-extra-arg-call.html
+/sdcard/android/layout_tests/fast/js/char-at.html
+/sdcard/android/layout_tests/fast/js/caller-property.html
+/sdcard/android/layout_tests/fast/js/bitwise-and-on-undefined.html
+/sdcard/android/layout_tests/fast/js/avl-crash.html
+/sdcard/android/layout_tests/fast/js/assign.html
+/sdcard/android/layout_tests/fast/js/ascii-regexp-subject.html
+/sdcard/android/layout_tests/fast/js/array-tostring-ignore-separator.html
+/sdcard/android/layout_tests/fast/js/array-tostring-and-join.html
+/sdcard/android/layout_tests/fast/js/array-splice.html
+/sdcard/android/layout_tests/fast/js/array-sort-reentrance.html
+/sdcard/android/layout_tests/fast/js/array-some.html
+/sdcard/android/layout_tests/fast/js/array-reset-large-index.html
+/sdcard/android/layout_tests/fast/js/array-map.html
+/sdcard/android/layout_tests/fast/js/array-lastIndexOf.html
+/sdcard/android/layout_tests/fast/js/array-join-bug-11524.html
+/sdcard/android/layout_tests/fast/js/array-iterate-backwards.html
+/sdcard/android/layout_tests/fast/js/array-indexof.html
+/sdcard/android/layout_tests/fast/js/array-indexing.html
+/sdcard/android/layout_tests/fast/js/array-index-immediate-types.html
+/sdcard/android/layout_tests/fast/js/array-holes.html
+/sdcard/android/layout_tests/fast/js/array-functions-non-arrays.html
+/sdcard/android/layout_tests/fast/js/array-foreach.html
+/sdcard/android/layout_tests/fast/js/array-float-delete.html
+/sdcard/android/layout_tests/fast/js/array-filter.html
+/sdcard/android/layout_tests/fast/js/array-every.html
+/sdcard/android/layout_tests/fast/js/arguments.html
+/sdcard/android/layout_tests/fast/js/arguments-bad-index.html
+/sdcard/android/layout_tests/fast/js/activation-proto.html
+/sdcard/android/layout_tests/fast/js/activation-object-function-lifetime.html
+/sdcard/android/layout_tests/fast/invalid/test-case-tr-th-td-should-not-close-dl-list.html
+/sdcard/android/layout_tests/fast/invalid/nestedh3s-rapidweaver.html
+/sdcard/android/layout_tests/fast/inspector/cssURLQuotes.html
+/sdcard/android/layout_tests/fast/innerHTML/javascript-url.html
+/sdcard/android/layout_tests/fast/innerHTML/innerHTML-custom-tag.html
+/sdcard/android/layout_tests/fast/innerHTML/innerHTML-case.html
+/sdcard/android/layout_tests/fast/innerHTML/additional-inline-style.html
+/sdcard/android/layout_tests/fast/innerHTML/005.html
+/sdcard/android/layout_tests/fast/inline/clean-after-removing-temp-boxes.html
+/sdcard/android/layout_tests/fast/images/text-content-crash.html
+/sdcard/android/layout_tests/fast/images/text-content-crash-2.html
+/sdcard/android/layout_tests/fast/images/load-img-with-empty-src.html
+/sdcard/android/layout_tests/fast/images/border.html
+/sdcard/android/layout_tests/fast/images/animated-background-image-crash.html
+/sdcard/android/layout_tests/fast/html/xhtml-serialize.html
+/sdcard/android/layout_tests/fast/html/script-allowed-types-languages.html
+/sdcard/android/layout_tests/fast/html/empty-fragment-id-goto-top.html
+/sdcard/android/layout_tests/fast/html/body-offset-properties.html
+/sdcard/android/layout_tests/fast/frames/viewsource-plain-text-tags.html
+/sdcard/android/layout_tests/fast/frames/set-unloaded-frame-location.html
+/sdcard/android/layout_tests/fast/frames/repaint-display-none-crash.html
+/sdcard/android/layout_tests/fast/frames/remove-frame-with-scrollbars-crash.html
+/sdcard/android/layout_tests/fast/frames/onload-remove-iframe-crash.html
+/sdcard/android/layout_tests/fast/frames/negative-remaining-length-crash.html
+/sdcard/android/layout_tests/fast/frames/location-put-after-removal.html
+/sdcard/android/layout_tests/fast/frames/location-change.html
+/sdcard/android/layout_tests/fast/frames/iframe-target.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-same-src.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-same-location.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-inner-html.html
+/sdcard/android/layout_tests/fast/frames/iframe-remove-after-id-change.html
+/sdcard/android/layout_tests/fast/frames/iframe-name-and-id.html
+/sdcard/android/layout_tests/fast/frames/iframe-js-url-clientWidth.html
+/sdcard/android/layout_tests/fast/frames/iframe-double-attach.html
+/sdcard/android/layout_tests/fast/frames/iframe-display-none.html
+/sdcard/android/layout_tests/fast/frames/hover-timer-crash.html
+/sdcard/android/layout_tests/fast/frames/frame-set-same-src.html
+/sdcard/android/layout_tests/fast/frames/frame-set-same-location.html
+/sdcard/android/layout_tests/fast/frames/frame-name-reset.html
+/sdcard/android/layout_tests/fast/frames/frame-display-none-focus.html
+/sdcard/android/layout_tests/fast/frames/empty-frame-document.html
+/sdcard/android/layout_tests/fast/frames/cross-site-this.html
+/sdcard/android/layout_tests/fast/frames/crash-removed-iframe.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-009.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-008.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-007.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-006.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-005.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-004.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-003.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-002.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-001.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-000.html
+/sdcard/android/layout_tests/fast/forms/textfield-focus-out.html
+/sdcard/android/layout_tests/fast/forms/textarea-trailing-newline.html
+/sdcard/android/layout_tests/fast/forms/textarea-setvalue-without-renderer.html
+/sdcard/android/layout_tests/fast/forms/textarea-setvalue-submit.html
+/sdcard/android/layout_tests/fast/forms/textarea-scrollbar-height.html
+/sdcard/android/layout_tests/fast/forms/textarea-linewrap-dynamic.html
+/sdcard/android/layout_tests/fast/forms/textarea-hard-linewrap-empty.html
+/sdcard/android/layout_tests/fast/forms/textarea-crlf.html
+/sdcard/android/layout_tests/fast/forms/text-set-value-crash.html
+/sdcard/android/layout_tests/fast/forms/tabs-with-modifiers.html
+/sdcard/android/layout_tests/fast/forms/tab-in-input.html
+/sdcard/android/layout_tests/fast/forms/submit-with-base.html
+/sdcard/android/layout_tests/fast/forms/submit-to-url-fragment.html
+/sdcard/android/layout_tests/fast/forms/submit-nil-value-field-assert.html
+/sdcard/android/layout_tests/fast/forms/slow-click.html
+/sdcard/android/layout_tests/fast/forms/selected-index-assert.html
+/sdcard/android/layout_tests/fast/forms/select-width-font-change.html
+/sdcard/android/layout_tests/fast/forms/select-type-ahead-list-box-no-selection.html
+/sdcard/android/layout_tests/fast/forms/select-set-inner.html
+/sdcard/android/layout_tests/fast/forms/select-reset.html
+/sdcard/android/layout_tests/fast/forms/select-replace-option.html
+/sdcard/android/layout_tests/fast/forms/select-remove-option.html
+/sdcard/android/layout_tests/fast/forms/select-out-of-bounds-index.html
+/sdcard/android/layout_tests/fast/forms/select-namedItem.html
+/sdcard/android/layout_tests/fast/forms/select-list-box-mouse-focus.html
+/sdcard/android/layout_tests/fast/forms/select-index-setter.html
+/sdcard/android/layout_tests/fast/forms/saved-state-adoptNode-crash.html
+/sdcard/android/layout_tests/fast/forms/remove-radio-button-assert.html
+/sdcard/android/layout_tests/fast/forms/range-reset.html
+/sdcard/android/layout_tests/fast/forms/range-default-value.html
+/sdcard/android/layout_tests/fast/forms/radio_checked_name.html
+/sdcard/android/layout_tests/fast/forms/radio-no-theme-padding.html
+/sdcard/android/layout_tests/fast/forms/radio-check-click-and-drag.html
+/sdcard/android/layout_tests/fast/forms/radio-button-no-change-event.html
+/sdcard/android/layout_tests/fast/forms/paste-multiline-text-input.html
+/sdcard/android/layout_tests/fast/forms/paste-into-textarea.html
+/sdcard/android/layout_tests/fast/forms/option-in-optgroup-removal.html
+/sdcard/android/layout_tests/fast/forms/option-constructor-selected.html
+/sdcard/android/layout_tests/fast/forms/option-change-single-selected.html
+/sdcard/android/layout_tests/fast/forms/old-names.html
+/sdcard/android/layout_tests/fast/forms/missing-action.html
+/sdcard/android/layout_tests/fast/forms/menulist-selection-reset.html
+/sdcard/android/layout_tests/fast/forms/menulist-no-renderer-onmousedown.html
+/sdcard/android/layout_tests/fast/forms/listbox-typeahead-empty.html
+/sdcard/android/layout_tests/fast/forms/listbox-scroll-after-options-removed.html
+/sdcard/android/layout_tests/fast/forms/input-zero-height-focus.html
+/sdcard/android/layout_tests/fast/forms/input-type-change-in-onfocus-mouse.html
+/sdcard/android/layout_tests/fast/forms/input-type-change-in-onfocus-keyboard.html
+/sdcard/android/layout_tests/fast/forms/input-setvalue-selection.html
+/sdcard/android/layout_tests/fast/forms/input-selection-hidden.html
+/sdcard/android/layout_tests/fast/forms/input-named-action-overrides-action-attribute.html
+/sdcard/android/layout_tests/fast/forms/input-changing-value.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-maxlength.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-elementFromPoint.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_selected.html
+/sdcard/android/layout_tests/fast/forms/hidden-input-not-enabled.html
+/sdcard/android/layout_tests/fast/forms/form-post-urlencoded.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart3.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart2.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding-normalization-overrun.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding-2.html
+/sdcard/android/layout_tests/fast/forms/focus-style-pending.html
+/sdcard/android/layout_tests/fast/forms/empty-get.html
+/sdcard/android/layout_tests/fast/forms/element-order.html
+/sdcard/android/layout_tests/fast/forms/element-by-name.html
+/sdcard/android/layout_tests/fast/forms/double-focus.html
+/sdcard/android/layout_tests/fast/forms/domstring-replace-crash.html
+/sdcard/android/layout_tests/fast/forms/document-write.html
+/sdcard/android/layout_tests/fast/forms/display-none-in-onchange-keyboard.html
+/sdcard/android/layout_tests/fast/forms/cursor-position.html
+/sdcard/android/layout_tests/fast/forms/button-in-forms-collection.html
+/sdcard/android/layout_tests/fast/forms/button-click-DOM.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-008.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-007.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-006.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-005.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-004.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-002.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-001.html
+/sdcard/android/layout_tests/fast/forms/autofocus-attribute.html
+/sdcard/android/layout_tests/fast/forms/add-remove-form-elements-stress-test.html
+/sdcard/android/layout_tests/fast/forms/activate-and-disabled-elements.html
+/sdcard/android/layout_tests/fast/forms/8250.html
+/sdcard/android/layout_tests/fast/forms/4628409.html
+/sdcard/android/layout_tests/fast/forms/11423.html
+/sdcard/android/layout_tests/fast/flexbox/inline-children-crash.html
+/sdcard/android/layout_tests/fast/events/window-load-capture.html
+/sdcard/android/layout_tests/fast/events/submit-reset-nested-bubble.html
+/sdcard/android/layout_tests/fast/events/stopPropagation-submit.html
+/sdcard/android/layout_tests/fast/events/stopPropagation-checkbox.html
+/sdcard/android/layout_tests/fast/events/space-scroll-event.html
+/sdcard/android/layout_tests/fast/events/simulated-key-state.html
+/sdcard/android/layout_tests/fast/events/shadow-boundary-crossing.html
+/sdcard/android/layout_tests/fast/events/selectstart-during-autoscroll.html
+/sdcard/android/layout_tests/fast/events/resize-subframe.html
+/sdcard/android/layout_tests/fast/events/remove-event-listener.html
+/sdcard/android/layout_tests/fast/events/programmatic-check-no-change-event.html
+/sdcard/android/layout_tests/fast/events/overflow-events.html
+/sdcard/android/layout_tests/fast/events/onunload-body-property.html
+/sdcard/android/layout_tests/fast/events/onsubmit-bubbling.html
+/sdcard/android/layout_tests/fast/events/onload-after-document-close-with-subresource.html
+/sdcard/android/layout_tests/fast/events/onload-after-document-close-no-subresource.html
+/sdcard/android/layout_tests/fast/events/onerror-bubbling.html
+/sdcard/android/layout_tests/fast/events/no-window-load.html
+/sdcard/android/layout_tests/fast/events/no-blur-on-page-leave.html
+/sdcard/android/layout_tests/fast/events/no-blur-on-enter-button.html
+/sdcard/android/layout_tests/fast/events/nested-window-event.html
+/sdcard/android/layout_tests/fast/events/nested-event-remove-node-crash.html
+/sdcard/android/layout_tests/fast/events/mouseup-outside-button.html
+/sdcard/android/layout_tests/fast/events/mousedown_in_scrollbar.html
+/sdcard/android/layout_tests/fast/events/message-port.html
+/sdcard/android/layout_tests/fast/events/message-port-inactive-document.html
+/sdcard/android/layout_tests/fast/events/message-port-deleted-frame.html
+/sdcard/android/layout_tests/fast/events/message-port-deleted-document.html
+/sdcard/android/layout_tests/fast/events/message-port-constructor-for-deleted-document.html
+/sdcard/android/layout_tests/fast/events/message-channel-listener-circular-ownership.html
+/sdcard/android/layout_tests/fast/events/message-channel-gc.html
+/sdcard/android/layout_tests/fast/events/message-channel-gc-3.html
+/sdcard/android/layout_tests/fast/events/message-channel-gc-2.html
+/sdcard/android/layout_tests/fast/events/keypress-removed-node.html
+/sdcard/android/layout_tests/fast/events/keydown-remove-frame.html
+/sdcard/android/layout_tests/fast/events/init-event-null-view.html
+/sdcard/android/layout_tests/fast/events/init-event-after-dispatch.html
+/sdcard/android/layout_tests/fast/events/event-targets.html
+/sdcard/android/layout_tests/fast/events/event-listener-html-non-html-confusion.html
+/sdcard/android/layout_tests/fast/events/event-instanceof.html
+/sdcard/android/layout_tests/fast/events/event-creation.html
+/sdcard/android/layout_tests/fast/events/div-focus.html
+/sdcard/android/layout_tests/fast/events/dispatch-to-handle-event.html
+/sdcard/android/layout_tests/fast/events/delayed-style-mutation-event-crash.html
+/sdcard/android/layout_tests/fast/events/caller-access-from-event-listener.html
+/sdcard/android/layout_tests/fast/events/anchor-empty-focus.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/logical.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/iso-ir-138.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/hebrew.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/csISO88598I.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8-i.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8-e.html
+/sdcard/android/layout_tests/fast/encoding/gbk/x-gbk.html
+/sdcard/android/layout_tests/fast/encoding/gbk/x-euc-cn.html
+/sdcard/android/layout_tests/fast/encoding/gbk/iso-ir-58.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gb_2312-80.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gbk.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gb2312.html
+/sdcard/android/layout_tests/fast/encoding/gbk/EUC-CN.html
+/sdcard/android/layout_tests/fast/encoding/gbk/csgb231280.html
+/sdcard/android/layout_tests/fast/encoding/gbk/csgb2312.html
+/sdcard/android/layout_tests/fast/encoding/gbk/cn-gb.html
+/sdcard/android/layout_tests/fast/encoding/gbk/close-gbk-converter.html
+/sdcard/android/layout_tests/fast/encoding/gbk/chinese.html
+/sdcard/android/layout_tests/fast/encoding/yahoo-mail.html
+/sdcard/android/layout_tests/fast/encoding/xml-charset-utf16.html
+/sdcard/android/layout_tests/fast/encoding/utf-32-little-endian-nobom.xml
+/sdcard/android/layout_tests/fast/encoding/utf-32-little-endian-bom.html
+/sdcard/android/layout_tests/fast/encoding/utf-32-big-endian-nobom.xml
+/sdcard/android/layout_tests/fast/encoding/utf-32-big-endian-bom.html
+/sdcard/android/layout_tests/fast/encoding/tag-in-title.html
+/sdcard/android/layout_tests/fast/encoding/script-in-head.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-4.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-3.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-2.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-tags-in-attributes.html
+/sdcard/android/layout_tests/fast/encoding/preload-encoding.html
+/sdcard/android/layout_tests/fast/encoding/noscript-in-head.html
+/sdcard/android/layout_tests/fast/encoding/no-charset-on-dynamic-script-load.html
+/sdcard/android/layout_tests/fast/encoding/namespace-tolerance.html
+/sdcard/android/layout_tests/fast/encoding/mispositioned-meta.html
+/sdcard/android/layout_tests/fast/encoding/misplaced-xml-declaration.html
+/sdcard/android/layout_tests/fast/encoding/meta-charset.html
+/sdcard/android/layout_tests/fast/encoding/latin1-winlatin.html
+/sdcard/android/layout_tests/fast/encoding/high-bit-latin1.html
+/sdcard/android/layout_tests/fast/encoding/hanarei-blog32-fc2-com.html
+/sdcard/android/layout_tests/fast/encoding/floraexpress-ru.html
+/sdcard/android/layout_tests/fast/encoding/decoder-allow-null-chars.html
+/sdcard/android/layout_tests/fast/encoding/css-link-charset.html
+/sdcard/android/layout_tests/fast/encoding/css-charset.html
+/sdcard/android/layout_tests/fast/encoding/css-charset-evil.html
+/sdcard/android/layout_tests/fast/encoding/css-charset-dom.html
+/sdcard/android/layout_tests/fast/encoding/charset-xuser-defined.html
+/sdcard/android/layout_tests/fast/encoding/charset-utf16.html
+/sdcard/android/layout_tests/fast/encoding/charset-unicode.html
+/sdcard/android/layout_tests/fast/encoding/charset-invalid.html
+/sdcard/android/layout_tests/fast/encoding/charset-cp1251.html
+/sdcard/android/layout_tests/fast/encoding/bom-in-content.html
+/sdcard/android/layout_tests/fast/encoding/bom-in-content-utf16.html
+/sdcard/android/layout_tests/fast/encoding/bandai-co-jp-releases.html
+/sdcard/android/layout_tests/fast/encoding/ahram-org-eg.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-common-root.html
+/sdcard/android/layout_tests/fast/dynamic/style-access-late-stylesheet-load.html
+/sdcard/android/layout_tests/fast/dynamic/recursive-layout.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-no-element.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentText.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentHTML.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentHTML-allowed-parents.html
+/sdcard/android/layout_tests/fast/dynamic/inline-to-block-crash.html
+/sdcard/android/layout_tests/fast/dynamic/hovered-detach.html
+/sdcard/android/layout_tests/fast/dynamic/float-remove-above-line.html
+/sdcard/android/layout_tests/fast/dynamic/checkbox-selection-crash.html
+/sdcard/android/layout_tests/fast/dynamic/ancestor-to-absolute.html
+/sdcard/android/layout_tests/fast/dynamic/5872671.html
+/sdcard/android/layout_tests/fast/dom/Window/window-special-properties.html
+/sdcard/android/layout_tests/fast/dom/Window/window-resize-and-move-sub-frame.html
+/sdcard/android/layout_tests/fast/dom/Window/window-remove-event-listener.html
+/sdcard/android/layout_tests/fast/dom/Window/window-property-shadowing.html
+/sdcard/android/layout_tests/fast/dom/Window/window-property-shadowing-name.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-top.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-self.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-self-from-other-frame.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-parent.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-parent-no-parent.html
+/sdcard/android/layout_tests/fast/dom/Window/window-object-cross-frame-calls.html
+/sdcard/android/layout_tests/fast/dom/Window/window-location-replace-functions.html
+/sdcard/android/layout_tests/fast/dom/Window/window-function-frame-getter-precedence.html
+/sdcard/android/layout_tests/fast/dom/Window/window-custom-prototype-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/window-closed-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/window-appendages-cleared.html
+/sdcard/android/layout_tests/fast/dom/Window/setTimeout-no-arguments.html
+/sdcard/android/layout_tests/fast/dom/Window/global-opener-function.html
+/sdcard/android/layout_tests/fast/dom/Window/getMatchedCSSRules-null-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/element-constructors-on-window.html
+/sdcard/android/layout_tests/fast/dom/Window/closure-access-after-navigation-iframe.html
+/sdcard/android/layout_tests/fast/dom/Window/attr-constructor.html
+/sdcard/android/layout_tests/fast/dom/Window/atob-btoa.html
+/sdcard/android/layout_tests/fast/dom/Window/alert-undefined.html
+/sdcard/android/layout_tests/fast/dom/TreeWalker/TreeWalker-currentNode.html
+/sdcard/android/layout_tests/fast/dom/Text/replaceWholeText.html
+/sdcard/android/layout_tests/fast/dom/StyleSheet/ownerNode-lifetime.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/viewless-document.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/not-supported-namespace-in-selector.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/elementRoot.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/dumpNodeList.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/dumpNodeList-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/detached-element.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseTag.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/bug-17313.html
+/sdcard/android/layout_tests/fast/dom/Range/range-processing-instructions.html
+/sdcard/android/layout_tests/fast/dom/Range/range-modifycontents.html
+/sdcard/android/layout_tests/fast/dom/Range/range-isPointInRange.html
+/sdcard/android/layout_tests/fast/dom/Range/range-intersectsNode.html
+/sdcard/android/layout_tests/fast/dom/Range/range-insertNode-splittext.html
+/sdcard/android/layout_tests/fast/dom/Range/range-insertNode-separate-endContainer.html
+/sdcard/android/layout_tests/fast/dom/Range/range-exceptions.html
+/sdcard/android/layout_tests/fast/dom/Range/range-comparePoint.html
+/sdcard/android/layout_tests/fast/dom/Range/range-compareNode.html
+/sdcard/android/layout_tests/fast/dom/Range/range-clone-empty.html
+/sdcard/android/layout_tests/fast/dom/Range/mutation.html
+/sdcard/android/layout_tests/fast/dom/Range/compareBoundaryPoints-2.html
+/sdcard/android/layout_tests/fast/dom/Range/compareBoundaryPoints-1.html
+/sdcard/android/layout_tests/fast/dom/Range/acid3-surround-contents.html
+/sdcard/android/layout_tests/fast/dom/Range/13000.html
+/sdcard/android/layout_tests/fast/dom/NodeList/item-by-id-with-no-document.html
+/sdcard/android/layout_tests/fast/dom/NodeList/invalidate-node-lists-when-parsing.html
+/sdcard/android/layout_tests/fast/dom/NodeList/childNodes-reset-cache.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-3.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-2.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-1.html
+/sdcard/android/layout_tests/fast/dom/Node/initial-values.html
+/sdcard/android/layout_tests/fast/dom/Node/DOMNodeRemovedEvent.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableSectionElement/rows.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableRowElement/insertCell.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableRowElement/cells.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/tBodies.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/rows.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/insert-row.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/early-acid3-66-excerpt.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/early-acid3-65-excerpt.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/cellpadding-attribute.html
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/options-collection-set-string-length.html
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/options-collection-detached.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-set-src.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-reexecution.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-load-events.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-decoding-error-after-setting-src.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/set-option-index-text.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/option-text.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/option-prototype.html
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/form/test1.html
+/sdcard/android/layout_tests/fast/dom/HTMLMetaElement/meta-attributes.html
+/sdcard/android/layout_tests/fast/dom/HTMLLabelElement/form/test1.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/size-attribute.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/size-as-number.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-text-reset.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-hidden-value.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-checked-reset.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/checked-pseudo-selector.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-without-renderer-width.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-src-absolute-url.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-natural-width-height.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-lowsrc-getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-longdesc-absolute-url.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-loading-gc.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/constructor-mutation-event-dispatch.html
+/sdcard/android/layout_tests/fast/dom/HTMLHtmlElement/set-version.html
+/sdcard/android/layout_tests/fast/dom/HTMLHtmlElement/duplicate-html-element-crash.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/head-check.html
+/sdcard/android/layout_tests/fast/dom/HTMLFormElement/elements-not-in-document.html
+/sdcard/android/layout_tests/fast/dom/HTMLFontElement/size-attribute.html
+/sdcard/android/layout_tests/fast/dom/HTMLElement/set-inner-outer-optimization.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/writeln-multiple-calls.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/writeln-call.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/write-multiple-calls.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/write-call.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/url-getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/title-set.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/title-get.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/object-by-name-unknown-child-element.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/object-by-name-or-id.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-special-properties.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-plugins.html
+/sdcard/android/layout_tests/fast/dom/HTMLDivElement/align/getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLButtonElement/value/getset.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/004.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/003.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/002.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/001.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/dumpNodeList.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/015.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/014.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/013.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/012.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/009.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/008.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/007.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/006.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/005.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/004.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/003.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/002.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/001.html
+/sdcard/android/layout_tests/fast/dom/EntityReference/readonly-exceptions.html
+/sdcard/android/layout_tests/fast/dom/Element/setAttribute-with-colon.html
+/sdcard/android/layout_tests/fast/dom/Element/setAttribute-case-insensitivity.html
+/sdcard/android/layout_tests/fast/dom/Element/onclick-case.html
+/sdcard/android/layout_tests/fast/dom/Element/offsetTop-table-cell.html
+/sdcard/android/layout_tests/fast/dom/Element/getAttribute-check-case-sensitivity.html
+/sdcard/android/layout_tests/fast/dom/Element/element-traversal.html
+/sdcard/android/layout_tests/fast/dom/Element/dimension-properties-unrendered.html
+/sdcard/android/layout_tests/fast/dom/Element/contains-method.html
+/sdcard/android/layout_tests/fast/dom/Element/attribute-uppercase.html
+/sdcard/android/layout_tests/fast/dom/Element/attr-param-typechecking.html
+/sdcard/android/layout_tests/fast/dom/DOMImplementation/createDocumentType-err.html
+/sdcard/android/layout_tests/fast/dom/DOMException/RangeException.html
+/sdcard/android/layout_tests/fast/dom/DOMException/prototype-object.html
+/sdcard/android/layout_tests/fast/dom/DOMException/EventException.html
+/sdcard/android/layout_tests/fast/dom/Document/title-property-set-multiple-times.html
+/sdcard/android/layout_tests/fast/dom/Document/title-property-creates-title-element.html
+/sdcard/android/layout_tests/fast/dom/Document/replaceChild-null-oldChild.html
+/sdcard/android/layout_tests/fast/dom/Document/replace-child.html
+/sdcard/android/layout_tests/fast/dom/Document/open-with-pending-load.html
+/sdcard/android/layout_tests/fast/dom/Document/document-reopen.html
+/sdcard/android/layout_tests/fast/dom/Document/document-charset.html
+/sdcard/android/layout_tests/fast/dom/Document/doc-open-while-parsing.html
+/sdcard/android/layout_tests/fast/dom/Document/createElementNS-namespace-err.html
+/sdcard/android/layout_tests/fast/dom/Document/createAttributeNS-namespace-err.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/transition-property-names.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/empty-string-property.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/css-properties-case-sensitive.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer-doctype2.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer-doctype.html
+/sdcard/android/layout_tests/fast/dom/xmlhttprequest-invalid-values.html
+/sdcard/android/layout_tests/fast/dom/xmlhttprequest-html-response-encoding.html
+/sdcard/android/layout_tests/fast/dom/wrapper-identity.html
+/sdcard/android/layout_tests/fast/dom/undetectable-style-filter.html
+/sdcard/android/layout_tests/fast/dom/undetectable-document-all.html
+/sdcard/android/layout_tests/fast/dom/title-text-property.html
+/sdcard/android/layout_tests/fast/dom/title-text-property-2.html
+/sdcard/android/layout_tests/fast/dom/timer-clear-interval-in-handler.html
+/sdcard/android/layout_tests/fast/dom/space-to-text.html
+/sdcard/android/layout_tests/fast/dom/setAttributeNS.html
+/sdcard/android/layout_tests/fast/dom/setAttribute-using-initial-input-value.html
+/sdcard/android/layout_tests/fast/dom/set-inner-text-newlines.html
+/sdcard/android/layout_tests/fast/dom/serialize-cdata.html
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex-multiple.html
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex-bug-12942.html
+/sdcard/android/layout_tests/fast/dom/script-element-without-frame-crash.html
+/sdcard/android/layout_tests/fast/dom/script-element-remove-self.html
+/sdcard/android/layout_tests/fast/dom/script-element-gc.html
+/sdcard/android/layout_tests/fast/dom/script-add.html
+/sdcard/android/layout_tests/fast/dom/resource-locations-in-created-html-document.html
+/sdcard/android/layout_tests/fast/dom/replace-first-child.html
+/sdcard/android/layout_tests/fast/dom/replace-child-siblings.html
+/sdcard/android/layout_tests/fast/dom/remove-style-element.html
+/sdcard/android/layout_tests/fast/dom/remove-named-attribute-crash.html
+/sdcard/android/layout_tests/fast/dom/Range-insertNode-crash.html
+/sdcard/android/layout_tests/fast/dom/prototypes.html
+/sdcard/android/layout_tests/fast/dom/prototype-chain.html
+/sdcard/android/layout_tests/fast/dom/plugin-attributes-enumeration.html
+/sdcard/android/layout_tests/fast/dom/outerText-no-element.html
+/sdcard/android/layout_tests/fast/dom/option-properties.html
+/sdcard/android/layout_tests/fast/dom/objc-big-method-name.html
+/sdcard/android/layout_tests/fast/dom/null-document-xmlhttprequest-open.html
+/sdcard/android/layout_tests/fast/dom/location-assign.html
+/sdcard/android/layout_tests/fast/dom/javascript-backslash.html
+/sdcard/android/layout_tests/fast/dom/innerHTML-nbsp.html
+/sdcard/android/layout_tests/fast/dom/innerHTML-escaping-attribute.html
+/sdcard/android/layout_tests/fast/dom/inner-width-height.html
+/sdcard/android/layout_tests/fast/dom/inner-text-with-no-renderer.html
+/sdcard/android/layout_tests/fast/dom/inner-text-rtl.html
+/sdcard/android/layout_tests/fast/dom/importNode-prefix.html
+/sdcard/android/layout_tests/fast/dom/importNode-null.html
+/sdcard/android/layout_tests/fast/dom/import-document-fragment.html
+/sdcard/android/layout_tests/fast/dom/import-attribute-node.html
+/sdcard/android/layout_tests/fast/dom/implementation-createHTMLDocument.html
+/sdcard/android/layout_tests/fast/dom/ImageDocument-image-deletion.html
+/sdcard/android/layout_tests/fast/dom/image-object.html
+/sdcard/android/layout_tests/fast/dom/iframe-document.html
+/sdcard/android/layout_tests/fast/dom/iframe-contentWindow-crash.html
+/sdcard/android/layout_tests/fast/dom/html-attribute-types.html
+/sdcard/android/layout_tests/fast/dom/getter-on-window-object2.html
+/sdcard/android/layout_tests/fast/dom/getter-on-window-object.html
+/sdcard/android/layout_tests/fast/dom/getelementbyname-invalidation.html
+/sdcard/android/layout_tests/fast/dom/generic-form-element-assert.html
+/sdcard/android/layout_tests/fast/dom/gc-7.html
+/sdcard/android/layout_tests/fast/dom/gc-6.html
+/sdcard/android/layout_tests/fast/dom/gc-5.html
+/sdcard/android/layout_tests/fast/dom/gc-4.html
+/sdcard/android/layout_tests/fast/dom/gc-3.html
+/sdcard/android/layout_tests/fast/dom/gc-2.html
+/sdcard/android/layout_tests/fast/dom/gc-11.html
+/sdcard/android/layout_tests/fast/dom/gc-1.html
+/sdcard/android/layout_tests/fast/dom/frame-contentWindow-crash.html
+/sdcard/android/layout_tests/fast/dom/features.html
+/sdcard/android/layout_tests/fast/dom/exception-no-frame-timeout-crash.html
+/sdcard/android/layout_tests/fast/dom/exception-no-frame-inline-script-crash.html
+/sdcard/android/layout_tests/fast/dom/everything-to-string.html
+/sdcard/android/layout_tests/fast/dom/element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/early-frame-url.html
+/sdcard/android/layout_tests/fast/dom/duplicate-ids.html
+/sdcard/android/layout_tests/fast/dom/duplicate-ids-document-order.html
+/sdcard/android/layout_tests/fast/dom/DOMParser-assign-variable.html
+/sdcard/android/layout_tests/fast/dom/domListEnumeration.html
+/sdcard/android/layout_tests/fast/dom/dom-instanceof.html
+/sdcard/android/layout_tests/fast/dom/documenturi-loses-to-base-tag.html
+/sdcard/android/layout_tests/fast/dom/documenturi-assigned-junk-implies-relative-urls-do-not-resolve.html
+/sdcard/android/layout_tests/fast/dom/documenturi-assigned-junk-implies-baseuri-null.html
+/sdcard/android/layout_tests/fast/dom/documenturi-affects-relative-paths.html
+/sdcard/android/layout_tests/fast/dom/documentElement-null.html
+/sdcard/android/layout_tests/fast/dom/document-scripts.html
+/sdcard/android/layout_tests/fast/dom/document-dir-property.html
+/sdcard/android/layout_tests/fast/dom/document-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/document-all-select.html
+/sdcard/android/layout_tests/fast/dom/document-all-input.html
+/sdcard/android/layout_tests/fast/dom/dir-no-body.html
+/sdcard/android/layout_tests/fast/dom/destroy-selected-radio-button-crash.html
+/sdcard/android/layout_tests/fast/dom/defaultView.html
+/sdcard/android/layout_tests/fast/dom/css-shortHands.html
+/sdcard/android/layout_tests/fast/dom/css-set-property-exception.html
+/sdcard/android/layout_tests/fast/dom/css-selectorText.html
+/sdcard/android/layout_tests/fast/dom/css-RGBValue.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-functions.html
+/sdcard/android/layout_tests/fast/dom/css-element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/css-dom-read.html
+/sdcard/android/layout_tests/fast/dom/css-dom-read-2.html
+/sdcard/android/layout_tests/fast/dom/createElementNS.html
+/sdcard/android/layout_tests/fast/dom/createElement.html
+/sdcard/android/layout_tests/fast/dom/createElement-with-column.xml
+/sdcard/android/layout_tests/fast/dom/createElement-with-column.html
+/sdcard/android/layout_tests/fast/dom/createDocumentType2.html
+/sdcard/android/layout_tests/fast/dom/createDocument.html
+/sdcard/android/layout_tests/fast/dom/createDocument-empty.html
+/sdcard/android/layout_tests/fast/dom/createAttribute-exception.html
+/sdcard/android/layout_tests/fast/dom/constructors-overriding.html
+/sdcard/android/layout_tests/fast/dom/constants.html
+/sdcard/android/layout_tests/fast/dom/computed-style-set-property.html
+/sdcard/android/layout_tests/fast/dom/compatMode-Strict.html
+/sdcard/android/layout_tests/fast/dom/compatMode-Compat.html
+/sdcard/android/layout_tests/fast/dom/compatMode-AlmostStrict.html
+/sdcard/android/layout_tests/fast/dom/comment-dom-node.html
+/sdcard/android/layout_tests/fast/dom/comment-document-fragment.html
+/sdcard/android/layout_tests/fast/dom/collection-null-like-arguments.html
+/sdcard/android/layout_tests/fast/dom/collection-namedItem-via-item.html
+/sdcard/android/layout_tests/fast/dom/clone-node-style.html
+/sdcard/android/layout_tests/fast/dom/clone-node-form-elements.html
+/sdcard/android/layout_tests/fast/dom/clone-node-form-elements-with-attr.html
+/sdcard/android/layout_tests/fast/dom/class-all-whitespace.html
+/sdcard/android/layout_tests/fast/dom/capturing-event-listeners.html
+/sdcard/android/layout_tests/fast/dom/canvasContext2d-element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/background-shorthand-csstext.html
+/sdcard/android/layout_tests/fast/dom/attribute-namespaces-get-set.html
+/sdcard/android/layout_tests/fast/dom/attribute-empty-value-no-children.html
+/sdcard/android/layout_tests/fast/dom/attribute-downcast-right.html
+/sdcard/android/layout_tests/fast/dom/attribute-case-sensitivity.html
+/sdcard/android/layout_tests/fast/dom/array-special-accessors-should-ignore-items.html
+/sdcard/android/layout_tests/fast/dom/anchor-toString.html
+/sdcard/android/layout_tests/fast/dom/anchor-backslash.html
+/sdcard/android/layout_tests/fast/doctypes/html-doctype.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-parsing.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-in-element.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-at-end.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-after-comment.html
+/sdcard/android/layout_tests/fast/doctypes/005-case-preserving.html
+/sdcard/android/layout_tests/fast/css-generated-content/reset-content-to-initial.html
+/sdcard/android/layout_tests/fast/css-generated-content/empty-content-with-float-crash.html
+/sdcard/android/layout_tests/fast/css/variables/invalid-identifier.html
+/sdcard/android/layout_tests/fast/css/counters/counter-number-input.html
+/sdcard/android/layout_tests/fast/css/counters/counter-function-input.html
+/sdcard/android/layout_tests/fast/css/counters/counter-function-input-2.html
+/sdcard/android/layout_tests/fast/css/word-break-user-modify-allowed-values.html
+/sdcard/android/layout_tests/fast/css/transition_shorthand_parsing.html
+/sdcard/android/layout_tests/fast/css/transition-timing-function.html
+/sdcard/android/layout_tests/fast/css/transform-function-lowercase-assert.html
+/sdcard/android/layout_tests/fast/css/stale-style-selector-crash-2.html
+/sdcard/android/layout_tests/fast/css/stale-style-selector-crash-1.html
+/sdcard/android/layout_tests/fast/css/sheet-title.html
+/sdcard/android/layout_tests/fast/css/remove-shorthand.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-005.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-004.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-003.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-002.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-001.html
+/sdcard/android/layout_tests/fast/css/pseudostyle-anonymous-text.html
+/sdcard/android/layout_tests/fast/css/parse-timing-function-crash.html
+/sdcard/android/layout_tests/fast/css/padding-no-renderer.html
+/sdcard/android/layout_tests/fast/css/overflow-property.html
+/sdcard/android/layout_tests/fast/css/outline-hidden-illegal-value.html
+/sdcard/android/layout_tests/fast/css/orphaned_units_crash.html
+/sdcard/android/layout_tests/fast/css/nested-rule-parent-sheet.html
+/sdcard/android/layout_tests/fast/css/min-device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/media-rule-dyn.html
+/sdcard/android/layout_tests/fast/css/max-height-and-max-width.html
+/sdcard/android/layout_tests/fast/css/max-device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/legacy-opacity-styles.html
+/sdcard/android/layout_tests/fast/css/invalid-rule-value.html
+/sdcard/android/layout_tests/fast/css/invalid-cursor-property-crash.html
+/sdcard/android/layout_tests/fast/css/insertRule-media.html
+/sdcard/android/layout_tests/fast/css/insertRule-font-face.html
+/sdcard/android/layout_tests/fast/css/import-style-update.html
+/sdcard/android/layout_tests/fast/css/hexColor-isDigit-assert.html
+/sdcard/android/layout_tests/fast/css/getPropertyValue-clip.html
+/sdcard/android/layout_tests/fast/css/getPropertyValue-border.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-zIndex-auto.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-relayout.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-borderRadius.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-spacing.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-image.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-box.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-background-size.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-background-position.html
+/sdcard/android/layout_tests/fast/css/font-property-priority.html
+/sdcard/android/layout_tests/fast/css/font-family-initial.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-families.html
+/sdcard/android/layout_tests/fast/css/font-face-descriptor-multiple-values-parsing.html
+/sdcard/android/layout_tests/fast/css/emptyStyleTag.html
+/sdcard/android/layout_tests/fast/css/empty-script.html
+/sdcard/android/layout_tests/fast/css/display-none-inline-style-change-crash.html
+/sdcard/android/layout_tests/fast/css/device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/dashboard-regions-attr-crash.html
+/sdcard/android/layout_tests/fast/css/CSSPrimitiveValue-exceptions.html
+/sdcard/android/layout_tests/fast/css/css-selector-text.html
+/sdcard/android/layout_tests/fast/css/css-properties-case-insensitive.html
+/sdcard/android/layout_tests/fast/css/computed-style-negative-top.html
+/sdcard/android/layout_tests/fast/css/computed-style-display-none.html
+/sdcard/android/layout_tests/fast/css/child-selector-implicit-tbody.html
+/sdcard/android/layout_tests/fast/css/case-transform.html
+/sdcard/android/layout_tests/fast/css/border-image-crash.html
+/sdcard/android/layout_tests/fast/css/background-position-serialize.html
+/sdcard/android/layout_tests/fast/css/background-position-inherit.html
+/sdcard/android/layout_tests/fast/css/background-currentcolor.html
+/sdcard/android/layout_tests/fast/cookies/local-file-can-set-cookies.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-4.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-3.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-2.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-1.html
+/sdcard/android/layout_tests/fast/canvas/toDataURL-noData.html
+/sdcard/android/layout_tests/fast/canvas/script-inside-canvas-fallback.html
+/sdcard/android/layout_tests/fast/canvas/radialGradient-infinite-values.html
+/sdcard/android/layout_tests/fast/canvas/pointInPath.html
+/sdcard/android/layout_tests/fast/canvas/linearGradient-infinite-values.html
+/sdcard/android/layout_tests/fast/canvas/pattern-with-transform.html
+/sdcard/android/layout_tests/fast/canvas/gradient-with-clip.html
+/sdcard/android/layout_tests/fast/canvas/gradient-addColorStop-with-invalid-color.html
+/sdcard/android/layout_tests/fast/canvas/drawImage-with-negative-source-destination.html
+/sdcard/android/layout_tests/fast/canvas/drawImage-with-invalid-args.html
+/sdcard/android/layout_tests/fast/canvas/create-pattern-does-not-crash.html
+/sdcard/android/layout_tests/fast/canvas/canvas-with-incorrect-args.html
+/sdcard/android/layout_tests/fast/canvas/canvas-putImageData.html
+/sdcard/android/layout_tests/fast/canvas/canvas-pattern-behaviour.html
+/sdcard/android/layout_tests/fast/canvas/canvas-path-with-inf-nan-dimensions.html
+/sdcard/android/layout_tests/fast/canvas/canvas-invalid-strokestyle.html
+/sdcard/android/layout_tests/fast/canvas/canvas-invalid-fillstyle.html
+/sdcard/android/layout_tests/fast/canvas/canvas-ImageData-behaviour.html
+/sdcard/android/layout_tests/fast/canvas/canvas-hides-fallback.html
+/sdcard/android/layout_tests/fast/canvas/arc-crash.html
+/sdcard/android/layout_tests/fast/canvas/access-zero-sized-canvas.html
diff --git a/tests/DumpRenderTree/run_layout_tests.py b/tests/DumpRenderTree/run_layout_tests.py
new file mode 100755
index 0000000..433271e
--- /dev/null
+++ b/tests/DumpRenderTree/run_layout_tests.py
@@ -0,0 +1,274 @@
+#!/usr/bin/python
+
+"""Run layout tests using Android emulator and instrumentation.
+
+  First, you need to get an SD card or sdcard image that has layout tests on it.
+  Layout tests are in following directory:
+    /sdcard/android/layout_tests
+  For example, /sdcard/android/layout_tests/fast
+
+  Usage:
+    Run all tests under fast/ directory:
+      run_layout_tests.py, or
+      run_layout_tests.py fast
+
+    Run all tests under a sub directory:
+      run_layout_tests.py fast/dom
+
+    Run a single test:
+      run_layout_tests.py fast/dom/
+
+  After a merge, if there are changes of layout tests in SD card, you need to
+  use --refresh-test-list option *once* to re-generate test list on the card.
+
+  Some other options are:
+    --time-out-ms (default is 8000 millis) for each test
+    --adb-options="-e" passes option string to adb
+    --results-directory=..., (default is ./layout-test-results) directory name under which results are stored.
+"""
+
+import logging
+import optparse
+import os
+import subprocess
+import sys
+import time
+
+def CountLineNumber(filename):
+  """Compute the number of lines in a given file.
+
+  Args:
+    filename: a file name related to the current directory.
+  """
+
+  fp = open(os.path.abspath(filename), "r");
+  lines = 0
+  for line in fp.readlines():
+    lines = lines + 1
+  fp.close()
+  return lines
+
+def DumpRenderTreeFinished(adb_cmd):
+  """ Check if DumpRenderTree finished running tests
+  
+  Args:
+    output: adb_cmd string
+  """
+  
+  # pull /sdcard/running_test.txt, if the content is "#DONE", it's done
+  shell_cmd_str = adb_cmd + " shell cat /sdcard/running_test.txt"
+  adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+  return adb_output.strip() == "#DONE"
+
+def DiffResults(marker, new_results, old_results, diff_results, strip_reason):
+   """ Given two result files, generate diff and
+       write to diff_results file. All arguments are absolute paths
+       to files.
+   """
+   old_file = open(old_results, "r")
+   new_file = open(new_results, "r")
+   diff_file = open(diff_results, "a") 
+
+   # Read lines from each file
+   ndict = new_file.readlines()
+   cdict = old_file.readlines()
+
+   # Write marker to diff file
+   diff_file.writelines(marker + "\n")
+   diff_file.writelines("###############\n")
+
+   # Strip reason from result lines
+   if strip_reason is True:
+     for i in range(0, len(ndict)):
+       ndict[i] = ndict[i].split(' ')[0] + "\n"
+     for i in range(0, len(cdict)):
+       cdict[i] = cdict[i].split(' ')[0] + "\n"
+
+   # Find results in new_results missing in old_results
+   new_count=0
+   for line in ndict:
+     if line not in cdict:
+       diff_file.writelines("+ " + line)
+       new_count += 1
+
+   # Find results in old_results missing in new_results
+   missing_count=0
+   for line in cdict:
+     if line not in ndict:
+       diff_file.writelines("- " + line)
+       missing_count += 1
+
+   logging.info(marker + "  >>> " + str(new_count) + " new, " + str(missing_count) + " misses")
+
+   diff_file.writelines("\n\n")
+
+   old_file.close()
+   new_file.close()
+   diff_file.close()
+   return
+
+def CompareResults(ref_dir, results_dir):
+  """Compare results in two directories
+
+  Args:
+    ref_dir: the reference directory having layout results as references
+    results_dir: the results directory
+  """
+  logging.info("Comparing results to " + ref_dir)
+
+  diff_result = os.path.join(results_dir, "layout_tests_diff.txt") 
+  if os.path.exists(diff_result):
+    os.remove(diff_result)
+
+  files=["passed", "failed", "nontext", "crashed"]
+  for f in files:
+    result_file_name = "layout_tests_" + f + ".txt"
+    DiffResults(f, os.path.join(results_dir, result_file_name),
+                os.path.join(ref_dir, result_file_name), diff_result,
+                f == "failed")
+  logging.info("Detailed diffs are in " + diff_result)
+
+def main(options, args):
+  """Run the tests. Will call sys.exit when complete.
+  
+  Args:
+    options: a dictionary of command line options
+    args: a list of sub directories or files to test
+  """
+
+  # Set up logging format.
+  log_level = logging.INFO
+  if options.verbose:
+    log_level = logging.DEBUG
+  logging.basicConfig(level=log_level,
+                      format='%(message)s')
+
+  # Include all tests if none are specified.
+  if not args:
+    path = 'fast';
+  else:
+    path = ' '.join(args);
+
+  adb_cmd = "adb ";
+  if options.adb_options:
+    adb_cmd += options.adb_options
+
+  # Re-generate the test list if --refresh-test-list is on
+  if options.refresh_test_list:
+    logging.info("Generating test list.");
+    shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#generateTestList -e path fast -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+    adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+
+    if adb_output.find('Process crashed') != -1:
+       logging.info("Aborting because cannot generate test list.\n" + adb_output)
+       sys.exit(1)
+
+
+  logging.info("Running tests")
+
+  # Count crashed tests.
+  crashed_tests = []
+
+  timeout_ms = '8000'
+  if options.time_out_ms:
+    timeout_ms = options.time_out_ms
+
+  # Run test until it's done
+
+  # Call LayoutTestsAutoTest::startLayoutTests.
+  shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#startLayoutTests -e path \"" + path + "\" -e timeout " + timeout_ms + " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+  adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+  while not DumpRenderTreeFinished(adb_cmd):
+    # Get the running_test.txt
+    logging.error("DumpRenderTree crashed, output:\n" + adb_output)
+
+    shell_cmd_str = adb_cmd + " shell cat /sdcard/running_test.txt"
+    crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
+    
+    logging.info(crashed_test + " CRASHED");
+    crashed_tests.append(crashed_test);
+
+    logging.info("Resuming layout test runner...");
+    # Call LayoutTestsAutoTest::resumeLayoutTests
+    shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#resumeLayoutTests -e path \"" + path + "\" -e timeout " + timeout_ms + " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+
+    adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+
+  if adb_output.find('INSTRUMENTATION_FAILED') != -1:
+    logging.error("Error happened : " + adb_output)
+    sys.exit(1)
+
+  logging.debug(adb_output);
+  logging.info("Done\n");
+
+  # Pull results from /sdcard
+  results_dir = options.results_directory
+  if not os.path.exists(results_dir):
+    os.makedirs(results_dir)
+  if not os.path.isdir(results_dir):
+    logging.error("Cannot create results dir: " + results_dir);
+    sys.exit(1);
+
+  result_files = ["/sdcard/layout_tests_passed.txt",
+                  "/sdcard/layout_tests_failed.txt",
+                  "/sdcard/layout_tests_nontext.txt"]
+  for file in result_files: 
+    shell_cmd_str = adb_cmd + " pull " + file + " " + results_dir
+    adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+    logging.debug(adb_output)
+    
+  # Create the crash list.
+  fp = open(results_dir + "/layout_tests_crashed.txt", "w");
+  fp.writelines(crashed_tests)
+  fp.close()
+
+  # Count the number of tests in each category.
+  passed_tests = CountLineNumber(results_dir + "/layout_tests_passed.txt")
+  logging.info(str(passed_tests) + " passed")
+  failed_tests = CountLineNumber(results_dir + "/layout_tests_failed.txt")
+  logging.info(str(failed_tests) + " failed")
+  crashed_tests = CountLineNumber(results_dir + "/layout_tests_crashed.txt")
+  logging.info(str(crashed_tests) + " crashed")
+  nontext_tests = CountLineNumber(results_dir + "/layout_tests_nontext.txt")
+  logging.info(str(nontext_tests) + " no dumpAsText")
+
+  logging.info("Results are stored under: " + results_dir + "\n")
+
+  # Comparing results to references to find new fixes and regressions.
+  results_dir = os.path.abspath(options.results_directory)
+  ref_dir = options.ref_directory
+
+  # if ref_dir is null, cannonify ref_dir to the script dir.
+  if not ref_dir:
+    script_self = sys.argv[0]
+    script_dir = os.path.dirname(script_self)
+    ref_dir = os.path.join(script_dir, "results")
+
+  ref_dir = os.path.abspath(ref_dir)
+
+  CompareResults(ref_dir, results_dir)
+
+if '__main__' == __name__:
+  option_parser = optparse.OptionParser()
+  option_parser.add_option("", "--time-out-ms",
+                           default=None,
+                           help="set the timeout for each test")
+  option_parser.add_option("", "--verbose", action="store_true",
+                           default=False,
+                           help="include debug-level logging")
+  option_parser.add_option("", "--refresh-test-list", action="store_true",
+                           default=False,
+                           help="re-generate test list, it may take some time.")
+  option_parser.add_option("", "--adb-options",
+                           default=None,
+                           help="pass options to adb, such as -d -e, etc");
+  option_parser.add_option("", "--results-directory",
+                           default="layout-test-results",
+                           help="directory which results are stored.")
+  option_parser.add_option("", "--ref-directory",
+                           default=None,
+                           dest="ref_directory",
+                           help="directory where reference results are stored.")
+
+  options, args = option_parser.parse_args();
+  main(options, args)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
new file mode 100644
index 0000000..a389461
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+import android.os.Handler;
+import android.os.Message;
+
+import java.util.HashMap;
+
+public class CallbackProxy extends Handler implements EventSender, LayoutTestController {
+    
+    private EventSender mEventSender;
+    private LayoutTestController mLayoutTestController;
+    
+    private static final int EVENT_DOM_LOG = 1;
+    private static final int EVENT_FIRE_KBD = 2;
+    private static final int EVENT_KEY_DOWN_1 = 3;
+    private static final int EVENT_KEY_DOWN_2 = 4;
+    private static final int EVENT_LEAP = 5;
+    private static final int EVENT_MOUSE_CLICK = 6;
+    private static final int EVENT_MOUSE_DOWN = 7;
+    private static final int EVENT_MOUSE_MOVE = 8;
+    private static final int EVENT_MOUSE_UP = 9;
+    
+    private static final int LAYOUT_CLEAR_LIST = 20;
+    private static final int LAYOUT_DISPLAY = 21;
+    private static final int LAYOUT_DUMP_TEXT = 22;
+    private static final int LAYOUT_DUMP_HISTORY = 23;
+    private static final int LAYOUT_DUMP_CHILD_SCROLL = 24;
+    private static final int LAYOUT_DUMP_EDIT_CB = 25;
+    private static final int LAYOUT_DUMP_SEL_RECT = 26;
+    private static final int LAYOUT_DUMP_TITLE_CHANGES = 27;
+    private static final int LAYOUT_KEEP_WEB_HISTORY = 28;
+    private static final int LAYOUT_NOTIFY_DONE = 29;
+    private static final int LAYOUT_QUEUE_BACK_NAV = 30;
+    private static final int LAYOUT_QUEUE_FWD_NAV = 31;
+    private static final int LAYOUT_QUEUE_LOAD = 32;
+    private static final int LAYOUT_QUEUE_RELOAD = 33;
+    private static final int LAYOUT_QUEUE_SCRIPT = 34;
+    private static final int LAYOUT_REPAINT_HORZ = 35;
+    private static final int LAYOUT_SET_ACCEPT_EDIT = 36;
+    private static final int LAYOUT_MAIN_FIRST_RESP = 37;
+    private static final int LAYOUT_SET_WINDOW_KEY = 38;
+    private static final int LAYOUT_TEST_REPAINT = 39;
+    private static final int LAYOUT_WAIT_UNTIL_DONE = 40;
+    
+    CallbackProxy(EventSender eventSender, 
+            LayoutTestController layoutTestController) {
+        mEventSender = eventSender;
+        mLayoutTestController = layoutTestController;
+    }
+    
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+        case EVENT_DOM_LOG:
+            mEventSender.enableDOMUIEventLogging(msg.arg1);
+            break;
+        case EVENT_FIRE_KBD:
+            mEventSender.fireKeyboardEventsToElement(msg.arg1);
+            break;
+        case EVENT_KEY_DOWN_1:
+            HashMap map = (HashMap) msg.obj;
+            mEventSender.keyDown((String) map.get("character"), 
+                    (String[]) map.get("withModifiers"));
+            break;
+
+        case EVENT_KEY_DOWN_2:
+            mEventSender.keyDown((String)msg.obj);
+            break;
+
+        case EVENT_LEAP:
+            mEventSender.leapForward(msg.arg1);
+            break;
+
+        case EVENT_MOUSE_CLICK:
+            mEventSender.mouseClick();
+            break;
+
+        case EVENT_MOUSE_DOWN:
+            mEventSender.mouseDown();
+            break;
+
+        case EVENT_MOUSE_MOVE:
+            mEventSender.mouseMoveTo(msg.arg1, msg.arg2);
+            break;
+
+        case EVENT_MOUSE_UP:
+            mEventSender.mouseUp();
+            break;
+
+        case LAYOUT_CLEAR_LIST:
+            mLayoutTestController.clearBackForwardList();
+            break;
+
+        case LAYOUT_DISPLAY:
+            mLayoutTestController.display();
+            break;
+
+        case LAYOUT_DUMP_TEXT:
+            mLayoutTestController.dumpAsText();
+            break;
+
+        case LAYOUT_DUMP_HISTORY:
+            mLayoutTestController.dumpBackForwardList();
+            break;
+
+        case LAYOUT_DUMP_CHILD_SCROLL:
+            mLayoutTestController.dumpChildFrameScrollPositions();
+            break;
+
+        case LAYOUT_DUMP_EDIT_CB:
+            mLayoutTestController.dumpEditingCallbacks();
+            break;
+
+        case LAYOUT_DUMP_SEL_RECT:
+            mLayoutTestController.dumpSelectionRect();
+            break;
+
+        case LAYOUT_DUMP_TITLE_CHANGES:
+            mLayoutTestController.dumpTitleChanges();
+            break;
+
+        case LAYOUT_KEEP_WEB_HISTORY:
+            mLayoutTestController.keepWebHistory();
+            break;
+
+        case LAYOUT_NOTIFY_DONE:
+            mLayoutTestController.notifyDone();
+            break;
+
+        case LAYOUT_QUEUE_BACK_NAV:
+            mLayoutTestController.queueBackNavigation(msg.arg1);
+            break;
+
+        case LAYOUT_QUEUE_FWD_NAV:
+            mLayoutTestController.queueForwardNavigation(msg.arg1);
+            break;
+
+        case LAYOUT_QUEUE_LOAD:
+            HashMap<String, String> loadMap = 
+                (HashMap<String, String>) msg.obj;
+            mLayoutTestController.queueLoad(loadMap.get("Url"), 
+                    loadMap.get("frameTarget"));
+            break;
+
+        case LAYOUT_QUEUE_RELOAD:
+            mLayoutTestController.queueReload();
+            break;
+
+        case LAYOUT_QUEUE_SCRIPT:
+            mLayoutTestController.queueScript((String)msg.obj);
+            break;
+
+        case LAYOUT_REPAINT_HORZ:
+            mLayoutTestController.repaintSweepHorizontally();
+            break;
+
+        case LAYOUT_SET_ACCEPT_EDIT:
+            mLayoutTestController.setAcceptsEditing(
+                    msg.arg1 == 1 ? true : false);
+            break;
+        case LAYOUT_MAIN_FIRST_RESP:
+            mLayoutTestController.setMainFrameIsFirstResponder(
+                    msg.arg1 == 1 ? true : false);
+            break;
+
+        case LAYOUT_SET_WINDOW_KEY:
+            mLayoutTestController.setWindowIsKey(
+                    msg.arg1 == 1 ? true : false);
+            break;
+
+        case LAYOUT_TEST_REPAINT:
+            mLayoutTestController.testRepaint();
+            break;
+
+        case LAYOUT_WAIT_UNTIL_DONE:
+            mLayoutTestController.waitUntilDone();
+            break;
+        }
+    }
+
+    // EventSender Methods
+    
+    public void enableDOMUIEventLogging(int DOMNode) {
+        obtainMessage(EVENT_DOM_LOG, DOMNode, 0).sendToTarget();
+    }
+
+    public void fireKeyboardEventsToElement(int DOMNode) {
+        obtainMessage(EVENT_FIRE_KBD, DOMNode, 0).sendToTarget();
+    }
+
+    public void keyDown(String character, String[] withModifiers) {
+        // TODO Auto-generated method stub
+        HashMap map = new HashMap();
+        map.put("character", character);
+        map.put("withModifiers", withModifiers);
+        obtainMessage(EVENT_KEY_DOWN_1, map).sendToTarget();
+    }
+
+    public void keyDown(String character) {
+        obtainMessage(EVENT_KEY_DOWN_2, character).sendToTarget();
+    }
+
+    public void leapForward(int milliseconds) {
+        obtainMessage(EVENT_LEAP, milliseconds, 0).sendToTarget(); 
+    }
+
+    public void mouseClick() {
+        obtainMessage(EVENT_MOUSE_CLICK).sendToTarget();
+    }
+
+    public void mouseDown() {
+        obtainMessage(EVENT_MOUSE_DOWN).sendToTarget();
+    }
+
+    public void mouseMoveTo(int X, int Y) {
+        obtainMessage(EVENT_MOUSE_MOVE, X, Y).sendToTarget();
+    }
+
+    public void mouseUp() {
+        obtainMessage(EVENT_MOUSE_UP).sendToTarget();
+    }
+    
+    // LayoutTestController Methods
+
+    public void clearBackForwardList() {
+        obtainMessage(LAYOUT_CLEAR_LIST).sendToTarget();
+    }
+
+    public void display() {
+        obtainMessage(LAYOUT_DISPLAY).sendToTarget();
+    }
+
+    public void dumpAsText() {
+        obtainMessage(LAYOUT_DUMP_TEXT).sendToTarget();
+    }
+
+    public void dumpBackForwardList() {
+        obtainMessage(LAYOUT_DUMP_HISTORY).sendToTarget();
+    }
+
+    public void dumpChildFrameScrollPositions() {
+        obtainMessage(LAYOUT_DUMP_CHILD_SCROLL).sendToTarget();
+    }
+
+    public void dumpEditingCallbacks() {
+        obtainMessage(LAYOUT_DUMP_EDIT_CB).sendToTarget(); 
+    }
+
+    public void dumpSelectionRect() {
+        obtainMessage(LAYOUT_DUMP_SEL_RECT).sendToTarget(); 
+    }
+
+    public void dumpTitleChanges() {
+        obtainMessage(LAYOUT_DUMP_TITLE_CHANGES).sendToTarget();
+    }
+
+    public void keepWebHistory() {
+        obtainMessage(LAYOUT_KEEP_WEB_HISTORY).sendToTarget();
+    }
+
+    public void notifyDone() {
+        obtainMessage(LAYOUT_NOTIFY_DONE).sendToTarget();
+    }
+
+    public void queueBackNavigation(int howfar) {
+        obtainMessage(LAYOUT_QUEUE_BACK_NAV, howfar, 0).sendToTarget();
+    }
+
+    public void queueForwardNavigation(int howfar) {
+        obtainMessage(LAYOUT_QUEUE_FWD_NAV, howfar, 0).sendToTarget();
+    }
+
+    public void queueLoad(String Url, String frameTarget) {
+        HashMap <String, String>map = new HashMap<String, String>();
+        map.put("Url", Url);
+        map.put("frameTarget", frameTarget);
+        obtainMessage(LAYOUT_QUEUE_LOAD, map).sendToTarget();
+    }
+
+    public void queueReload() {
+        obtainMessage(LAYOUT_QUEUE_RELOAD).sendToTarget();
+    }
+
+    public void queueScript(String scriptToRunInCurrentContext) {
+        obtainMessage(LAYOUT_QUEUE_SCRIPT, 
+                scriptToRunInCurrentContext).sendToTarget();
+    }
+
+    public void repaintSweepHorizontally() {
+        obtainMessage(LAYOUT_REPAINT_HORZ).sendToTarget();
+    }
+
+    public void setAcceptsEditing(boolean b) {
+        obtainMessage(LAYOUT_SET_ACCEPT_EDIT, b ? 1 : 0, 0).sendToTarget();
+    }
+
+    public void setMainFrameIsFirstResponder(boolean b) {
+        obtainMessage(LAYOUT_MAIN_FIRST_RESP, b ? 1 : 0, 0).sendToTarget();
+    }
+
+    public void setWindowIsKey(boolean b) {
+        obtainMessage(LAYOUT_SET_WINDOW_KEY,b ? 1 : 0, 0).sendToTarget();
+    }
+
+    public void testRepaint() {
+        obtainMessage(LAYOUT_TEST_REPAINT).sendToTarget(); 
+    }
+
+    public void waitUntilDone() {
+        obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget();
+    }
+
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java
new file mode 100644
index 0000000..82fd8d8
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+public interface EventSender {
+    	public void mouseDown();
+    	public void mouseUp();
+        public void mouseClick();
+        public void mouseMoveTo(int X, int Y);
+        public void leapForward(int milliseconds);
+        public void keyDown (String character, String[] withModifiers);
+        public void keyDown (String character);
+        public void enableDOMUIEventLogging(int DOMNode);
+        public void fireKeyboardEventsToElement(int DOMNode);
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
new file mode 100644
index 0000000..9be33db
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import android.util.*;
+
+public class FileFilter {
+
+    public static boolean ignoreTest(String file) {
+      // treat files like directories for the time being.
+      for (int i = 0; i < ignoreTestList.length; i ++) {
+          if (file.endsWith(ignoreTestList[i])) {
+             Log.e("FileFilter", "File path in IgnoreTest: " + file); 
+             return true;
+          }
+      }
+      for (int i = 0; i < ignoreTestDirs.length; i++) {
+          if (file.endsWith(ignoreTestDirs[i])) {
+              Log.e("FileFilter", "File path in ignore list: " + file);
+              return true;
+          }
+      }
+      
+      return false;
+    }
+ 
+    public static boolean ignoreResults(String file) {
+        int index = file.indexOf("fast");
+        if (index != -1) {
+            String sub = file.substring(index);
+            if (ignoreResultList.contains(sub))
+                return true;
+        }
+        return false;
+
+    }
+
+    public static String isKnownBug(String file) {
+        int index = file.indexOf("fast");
+        if (index != -1) {
+            String sub = file.substring(index);
+            // Log.e("FileFilter", "Looking for:"+sub);
+            if (bugList.containsKey(sub))
+                return bugList.get(sub);
+        }
+        return null;
+    }
+
+    final static HashSet<String> ignoreResultList = new HashSet<String>();
+    final static Hashtable<String, String> bugList = 
+        new Hashtable<String, String>();
+ 
+    static {
+        fillIgnoreResultSet();
+        fillBugTable();
+    }
+
+    static final String[] ignoreTestDirs = {
+        ".", // ignore hidden directories and files
+        "resources", // ignore resource directories
+        "AppleScript", // AppleScript not supported
+        "xpath", // xpath requires libxml2, not supported
+        "xsl", //xsl requires libxml2 & libxslt, not sup.
+        "kde", // don't run kde tests.
+        ".svn", // don't run anything under .svn folder
+        "gradients", // known crash
+        "profiler"  // profiler is not supported
+    };
+        
+    static final String [] ignoreTestList = {
+        "toString-stack-overflow.html", // Crashes #606688
+        "frame-limit.html", // generates too many GREFs
+        "css-insert-import-rule.html", // Crashes, #717414
+        "input-text-enter.html", // Crashes. #735088
+        "text-shadow-extreme-value.html", // Crashes #571671
+        "reflection-masks.html",
+        "frame-creation-removal.html",
+        "large-expressions.html",
+        "null-page-show-modal-dialog-crash.html",
+        "font-face-implicit-local-font.html",
+        "font-face-locally-installed.html",
+        "beforeSelectorOnCodeElement.html",
+        "cssTarget-crash.html",
+        "searchfield-heights.html", // Bug 1570692
+        "tabindex-focus-blur-all.html",
+        "search-rtl.html" // fast/forms/search-rtl.html
+        };
+    
+    static void fillIgnoreResultSet() {
+        // need test plugin
+        ignoreResultList.add("fast/dom/Window/Plug-ins.html");
+        // pixel depth
+        ignoreResultList.add("fast/dom/Window/window-screen-properties.html");
+        // missing space in textrun, ok as text is wrapped. ignore. #714933
+        ignoreResultList.add("fast/events/onload-webkit-before-webcore.html");
+        // missing support for textInputController.makeAttributedString()
+        ignoreResultList.add("fast/forms/attributed-strings.html");
+        // charset convert. #516936 ignore, won't fix
+        ignoreResultList.add("fast/forms/form-data-encoding-2.html");
+        // charset convert. #516936 ignore, won't fix
+        ignoreResultList.add("fast/forms/form-data-encoding.html");
+        // execCommand "insertText" not supported
+        ignoreResultList.add("fast/forms/input-appearance-maxlength.html");
+        // Copy&Paste commands not supported
+        ignoreResultList.add("fast/forms/input-truncate-newline.html");
+        ignoreResultList.add("fast/forms/textarea-paste-newline.html");
+        // requires eventSender.mouseMoveTo, mouseDown & mouseUp and 
+        // abs. position of mouse to select a word. ignore, won't fix #716583
+        ignoreResultList.add("fast/forms/onselect-textarea.html");
+        // requires eventSender.mouseMoveTo, mouseDown & mouseUp and 
+        // abs. position of mouse to select a word. ignore, won't fix #716583
+        ignoreResultList.add("fast/forms/onselect-textfield.html");
+        // not implemented queryCommandEnabled:BackColor, Undo & Redo
+        ignoreResultList.add("fast/forms/plaintext-mode-1.html");
+        // Our text areas are a little thinner than Apples. Also RTL test failes
+        ignoreResultList.add("fast/forms/textarea-appearance-wrap.html");
+        // Our text areas are a little thinner than Apples
+        ignoreResultList.add("fast/forms/textarea-hard-linewrap.html");
+        // screen width&height are different
+        ignoreResultList.add("fast/frames/frameElement-widthheight.html");
+        ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html");
+        //  requires JS test API, textInputController
+        ignoreResultList.add("fast/text/attributed-substring-from-range.html"); 
+        ignoreResultList.add("fast/text/attributed-substring-from-range-001.html");
+        // will not fix #619707
+        ignoreResultList.add("fast/css/case-transform.html");
+        // different platform defaults for font and different screen size
+        ignoreResultList.add("fast/css/computed-style.html");
+        // different screen size result in extra spaces in Apple compared to us
+        ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html");
+        // xslt and xpath elements missing from property list
+        ignoreResultList.add("fast/dom/Window/window-properties.html");
+        // requires textInputController.characterIndexForPoint
+        ignoreResultList.add("fast/dom/character-index-for-point.html");
+        // requires xpath support
+        ignoreResultList.add("fast/dom/gc-9.html");
+        // requires xslt and xpath support
+        ignoreResultList.add("fast/dom/global-constructors.html");
+        // dynamic plugins not supported
+        ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html");
+        ignoreResultList.add("fast/js/navigator-mimeTypes-length.html");
+        // there is extra spacing in the file due to multiple input boxes
+        // fitting on one line on Apple, ours are wrapped. Space at line ends
+        // are stripped.
+        ignoreResultList.add("fast/dom/tabindex-clamp.html");
+        
+        // requires eventSender.mouseDown(),mouseUp()
+        ignoreResultList.add("fast/dom/Window/window-xy-properties.html");
+        ignoreResultList.add("fast/events/window-events-bubble.html");
+        ignoreResultList.add("fast/events/window-events-bubble2.html");
+        ignoreResultList.add("fast/events/window-events-capture.html");
+        ignoreResultList.add("fast/forms/select-empty-list.html");
+        ignoreResultList.add("fast/replaced/image-map.html");
+        ignoreResultList.add("fast/events/capture-on-target.html");
+        ignoreResultList.add("fast/events/dblclick-addEventListener.html");
+        ignoreResultList.add("fast/events/drag-in-frames.html");
+        ignoreResultList.add("fast/events/drag-outside-window.html");
+        ignoreResultList.add("fast/events/event-sender-mouse-click.html");
+        ignoreResultList.add("fast/events/event-view-toString.html");
+        ignoreResultList.add("fast/events/frame-click-focus.html");
+        ignoreResultList.add("fast/events/input-image-scrolled-x-y.html");
+        ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html");
+        ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html");
+        ignoreResultList.add("fast/events/mouseover-mouseout.html");
+        ignoreResultList.add("fast/events/mouseover-mouseout2.html");
+        ignoreResultList.add("fast/events/mouseup-outside-button.html");
+        ignoreResultList.add("fast/events/mouseup-outside-document.html");
+        ignoreResultList.add("fast/events/onclick-list-marker.html");
+        ignoreResultList.add("fast/events/ondragenter.html");
+        ignoreResultList.add("fast/forms/drag-into-textarea.html");
+        ignoreResultList.add("fast/forms/input-select-on-click.html");
+        ignoreResultList.add("fast/forms/listbox-onchange.html");
+        ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html");
+        ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html");
+        
+        // there is extra spacing in the file due to multiple frame boxes
+        // fitting on one line on Apple, ours are wrapped. Space at line ends
+        // are stripped.
+        ignoreResultList.add("fast/events/iframe-object-onload.html");
+        // eventSender.mouseDown(), mouseUp() and objc API missing
+        ignoreResultList.add("fast/events/mouseup-outside-document.html");
+        ignoreResultList.add("fast/events/objc-keyboard-event-creation.html");
+        ignoreResultList.add("fast/events/objc-event-api.html");
+        // not capturing the console messages
+        ignoreResultList.add("fast/forms/selected-index-assert.html");
+        ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html");
+        // there is extra spacing as the text areas and input boxes fit next
+        // to each other on Apple, but are wrapped on our screen.
+        ignoreResultList.add("fast/forms/selection-functions.html");
+        // Text selection done differently on our platform. When a inputbox
+        // gets focus, the entire block is selected.
+        ignoreResultList.add("fast/forms/textarea-initial-caret-position.html");
+        ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html");
+        // Requires LayoutTests to exist at /tmp/LayoutTests
+        ignoreResultList.add("fast/loader/local-JavaScript-from-local.html");
+        ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html");
+        // extra spacing because iFrames rendered next to each other on Apple
+        ignoreResultList.add("fast/loader/opaque-base-url.html");
+        // RegExp is too large, causing OOM
+        ignoreResultList.add("fast/js/regexp-charclass-crash.html");
+        ignoreResultList.add("fast/text/plain-text-line-breaks.html");
+        
+        
+    }
+    
+    static void fillBugTable() {
+        bugList.put("fast/forms/check-box-enter-key.html", "716715");
+        bugList.put("fast/forms/focus-control-to-page.html", "716638");
+        bugList.put("fast/html/tab-order.html", "719289");
+        bugList.put("fast/dom/attribute-namespaces-get-set.html", "733229");
+        bugList.put("fast/dom/location-hash.html", "733822");
+        bugList.put("fast/dom/set-innerHTML.html", "733823");
+        bugList.put("fast/dom/xmlhttprequest-get.html", "733846");
+        bugList.put("fast/encoding/css-charset-default.html", "733856");
+        bugList.put("fast/encoding/default-xhtml-encoding.html", "733882");
+        bugList.put("fast/encoding/meta-in-xhtml.html", "733882");
+        bugList.put("fast/events/frame-tab-focus.html", "734308");
+        bugList.put("fast/events/keydown-keypress-focus-change.html", "653224");
+        bugList.put("fast/events/keypress-focus-change.html", "653224");
+        bugList.put("fast/events/option-tab.html", "734308");
+        bugList.put("fast/forms/focus2.html", "735111");
+        bugList.put("fast/forms/listbox-selection.html", "735116");
+        bugList.put("fast/forms/search-event-delay.html", "735120");
+        bugList.put("fast/frames/iframe-window-focus.html", "735140");
+        bugList.put("fast/innerHTML/004.html", "733882");
+        bugList.put("fast/js/date-DST-time-cusps.html", "735144");
+        bugList.put("fast/js/string-capitalization.html", "516936");
+        bugList.put("fast/js/string-concatenate-outofmemory.html","735152");
+        bugList.put("fast/parser/external-entities.html", "735176");
+        bugList.put("fast/events/div-focus.html", "735185");
+        bugList.put("fast/overflow/scroll-vertical-not-horizontal.html", "735196");
+        bugList.put("fast/events/arrow-navigation.html", "735233");
+        bugList.put("fast/forms/select-type-ahead-non-latin.html", "735244");
+        bugList.put("fast/events/js-keyboard-event-creation.html", "735255");
+        
+    }
+    
+    
+    
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
new file mode 100644
index 0000000..d685f5d
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.io.File;
+
+import android.app.ListActivity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+import android.os.Bundle;
+
+
+public abstract class FileList extends ListActivity 
+{
+	public boolean onKeyDown(int keyCode, KeyEvent event) {
+		switch (keyCode)
+		{
+			case KeyEvent.KEYCODE_DPAD_LEFT:
+				if (mPath.length() > mBaseLength) {
+					File f = new File(mPath);
+					mFocusFile = f.getName(); 
+					mFocusIndex = 0;
+					f = f.getParentFile();
+					mPath = f.getPath();
+					updateList();
+					return true;
+				}
+				break;
+				
+			case KeyEvent.KEYCODE_DPAD_RIGHT:
+				{
+					Map map = (Map) getListView().getItemAtPosition(getListView().getSelectedItemPosition());
+					String path = (String)map.get("path");
+					if ((new File(path)).isDirectory()) {
+						mPath = path;
+				        mFocusFile = null;
+						updateList();
+					} else {
+						processFile(path, false);
+					}
+                    return true;
+				}
+	
+			default:
+				break;
+		}
+		return super.onKeyDown(keyCode, event);
+	}
+
+	public void onCreate(Bundle icicle) 
+    {
+        super.onCreate(icicle);
+        setupPath();
+        updateList();
+    }
+    
+    protected List getData()
+    {
+        List myData = new ArrayList<HashMap>();
+        
+        File f = new File(mPath);
+        if (!f.exists()) {
+        	addItem(myData, "!LayoutTests path missing!", "");
+        	return myData;
+        }
+        String[] files = f.list();
+ 
+        for (int i = 0; i < files.length; i++) {
+        	StringBuilder sb = new StringBuilder(mPath);
+        	sb.append(File.separatorChar);
+        	sb.append(files[i]);
+        	String path = sb.toString();
+        	File c = new File(path);
+        	if (fileFilter(c)) {
+	        	if (c.isDirectory()) {
+	        		addItem(myData, "<"+files[i]+">", path);
+	        		if (mFocusFile != null && mFocusFile.equals(files[i]))
+	        			mFocusIndex = myData.size()-1;
+	        	}
+	        	else
+	        	    addItem(myData, files[i], path);
+        	}
+        }
+        
+        return myData;
+    }
+    
+    protected void addItem(List<Map> data, String name, String path)
+    {
+        HashMap temp = new HashMap();
+        temp.put("title", name);
+        temp.put("path", path);
+        data.add(temp);
+    }
+    
+    protected void onListItemClick(ListView l, View v, int position, long id)
+    {
+    	Map map = (Map) l.getItemAtPosition(position);
+    	String path = (String)map.get("path");
+
+        if ((new File(path)).isDirectory()) {
+            mPath = path;
+            mFocusFile = null;
+            updateList();
+        } else {
+            processFile(path, false);
+        }
+    }
+    
+    /*
+     * This function is called when the user has selected a file in the
+     * file list. The selected file could be a file or a directory.
+     * The flag indicates if this was from a selection or not.
+     */
+    abstract void processFile(String filename, boolean selection);
+    
+    /*
+     * This function is called when the file list is being built. Return
+     * true if the file is to be added to the file list.
+     */
+    abstract boolean fileFilter(File f);
+    
+    protected void updateList() {
+        setListAdapter(new SimpleAdapter(this,
+                getData(),
+                android.R.layout.simple_list_item_1,
+                new String[] {"title"},
+                new int[] {android.R.id.text1}));
+        String title = mPath; //.substring(mBaseLength-11); // show the word LayoutTests
+        setTitle(title);
+        getListView().setSelection(mFocusIndex);
+    }
+    
+    protected void setupPath() 
+    {
+    	mPath = "/sdcard/android/layout_tests";
+    	mBaseLength = mPath.length();
+    }
+    
+    protected String mPath;
+    protected int mBaseLength;
+    protected String mFocusFile;
+    protected int mFocusIndex;
+  
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
new file mode 100644
index 0000000..86bfad7
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.Vector;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.ViewGroup;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.widget.LinearLayout;
+import android.os.*;
+
+// TestRecorder creates two files, one for passing tests
+// and another for failing tests and writes the paths to
+// layout tests one line at a time. TestRecorder does not
+// have ability to clear the results.
+class TestRecorder {
+    public void passed(String layout_file) {
+      try {
+          mBufferedOutputPassedStream.write(layout_file.getBytes());
+          mBufferedOutputPassedStream.write('\n');
+          mBufferedOutputPassedStream.flush();
+      } catch(Exception e) {
+          e.printStackTrace();
+      }
+   }
+
+    public void failed(String layout_file, String reason) {
+      try {
+          mBufferedOutputFailedStream.write(layout_file.getBytes());
+          mBufferedOutputFailedStream.write(" : ".getBytes());
+          mBufferedOutputFailedStream.write(reason.getBytes());
+          mBufferedOutputFailedStream.write('\n');
+          mBufferedOutputFailedStream.flush();
+      } catch(Exception e) {
+          e.printStackTrace();
+      }
+    }
+
+    public void nontext(String layout_file, boolean has_results) {
+      try {
+          mBufferedOutputNontextStream.write(layout_file.getBytes());
+          if (has_results) {
+              mBufferedOutputNontextStream.write(" : has expected results".getBytes());
+          }
+          mBufferedOutputNontextStream.write('\n');
+          mBufferedOutputNontextStream.flush();
+      } catch(Exception e) {
+          e.printStackTrace();
+      }
+    }
+
+    public TestRecorder(boolean resume) {
+      try {
+      File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
+      File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
+      File resultsNontextFile = new File("/sdcard/layout_tests_nontext.txt");
+ 
+      mBufferedOutputPassedStream =
+          new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
+      mBufferedOutputFailedStream =
+          new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume));
+      mBufferedOutputNontextStream =
+          new BufferedOutputStream(new FileOutputStream(resultsNontextFile, resume));
+      } catch (Exception e) {
+          e.printStackTrace();
+      }
+    }
+
+    public void close() {
+        try {
+            mBufferedOutputPassedStream.close();
+            mBufferedOutputFailedStream.close();
+            mBufferedOutputNontextStream.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    private BufferedOutputStream mBufferedOutputPassedStream;
+    private BufferedOutputStream mBufferedOutputFailedStream;
+    private BufferedOutputStream mBufferedOutputNontextStream;
+}
+
+public class HTMLHostActivity extends Activity 
+     implements LayoutTestController {
+
+    public class AsyncHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == MSG_TIMEOUT) {
+                mTimedOut = true;
+                requestWebKitData();
+                return;
+            } else if (msg.what == MSG_WEBKIT_DATA) {
+                HTMLHostActivity.this.dump(mTimedOut, (String)msg.obj);
+                return;
+            }
+
+            super.handleMessage(msg);
+        }
+    }
+
+    public void requestWebKitData() {
+        Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA);
+        
+        if (mRequestedWebKitData)
+            throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
+        
+        mRequestedWebKitData = true;
+        if (mDumpAsText) { 
+            mWebView.documentAsText(callback);
+        } else {
+            mWebView.externalRepresentation(callback);
+        }
+    }
+    // Activity methods
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        LinearLayout contentView = new LinearLayout(this);
+        contentView.setOrientation(LinearLayout.VERTICAL);
+        setContentView(contentView);
+
+        mWebView = new WebView(this);
+        mWebView.getSettings().setJavaScriptEnabled(true);
+        mWebView.setWebChromeClient(mChromeClient);
+        mEventSender = new WebViewEventSender(mWebView);
+        mCallbackProxy = new CallbackProxy(mEventSender, this);
+        mFinishedRunning = false;
+
+        mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
+        mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
+        contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
+ 
+        mHandler = new AsyncHandler();
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Bundle savedInstanceState) {
+        super.onRestoreInstanceState(savedInstanceState);
+    }
+
+    private void getTestList() {
+        // Read test list.
+        try {
+            BufferedReader inReader = new BufferedReader(new FileReader(LAYOUT_TESTS_LIST_FILE));
+            String line = inReader.readLine();
+            while (line != null) {
+                if (line.startsWith(mTestPathPrefix))
+                    mTestList.add(line);
+                line = inReader.readLine();
+            }
+            inReader.close();
+            Log.v(LOGTAG, "Test list has " + mTestList.size() + " test(s).");
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
+        }
+    }
+    
+    private void resumeTestList() {
+        // read out the test name it stoped last time.
+        try {
+            BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE));
+            String line = inReader.readLine();
+            for (int i = 0; i < mTestList.size(); i++) {
+                if (mTestList.elementAt(i).equals(line)) {
+                    mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size()));
+                    break;
+                }
+            }
+            inReader.close();
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
+        }
+    }
+    
+    private void clearTestStatus() {
+        // Delete TEST_STATUS_FILE
+        try {
+            File f = new File(TEST_STATUS_FILE);
+            if (f.delete())
+                Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE);
+            else
+                Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE);
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage());
+        }
+    }
+    
+    private void updateTestStatus(String s) {
+        // Write TEST_STATUS_FILE
+        try {
+            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE));
+            bos.write(s.getBytes());
+            bos.close();
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE);
+        }
+    }
+    
+    protected void onResume() {
+        super.onResume();
+        if (mTestList == null)
+            mTestList = new Vector<String>();
+        
+        if (mTestList.isEmpty()) {
+            // Read settings
+            Intent intent = getIntent();
+            mTestPathPrefix = intent.getStringExtra(TEST_PATH_PREFIX);
+            mSingleTestMode = intent.getBooleanExtra(SINGLE_TEST_MODE, false);
+            boolean resume = intent.getBooleanExtra(RESUME_FROM_CRASH, false);
+            mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 8000);
+            
+            mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+            
+            if (mTestPathPrefix == null)
+                throw new AssertionError("mTestPathPrefix cannot be null");
+            
+            Log.v(LOGTAG, "Run tests with prefix: " + mTestPathPrefix);
+
+            mResultRecorder = new TestRecorder(resume);
+            
+            if (!resume)
+                clearTestStatus();
+            
+            if (!mSingleTestMode) {
+                getTestList();
+                if (resume)
+                    resumeTestList();
+            } else {
+                mTestList.add(mTestPathPrefix);
+            }
+            
+            if (!mTestList.isEmpty())
+                runTestAtIndex(0);
+            else
+                mWebView.loadUrl("about:");
+        }
+    }
+
+    protected void onStop() {
+        super.onStop();
+        mWebView.stopLoading();
+    }
+
+    protected void onDestroy() {
+        super.onDestroy();
+        mResultRecorder.close();
+        mWebView.destroy();
+        mWebView = null;
+    }
+    
+    public void onLowMemory() {
+        super.onLowMemory();
+        // Simulate a crash
+        Log.e(LOGTAG, "Low memory, killing self");
+        System.exit(1);
+    }
+
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        // Log key strokes as they don't seem to be matched
+        //Log.e(LOGTAG, "Event: "+event);
+        return super.dispatchKeyEvent(event);
+    }
+
+    // Run a test at specified index in the test list.
+    // Stops activity if run out of tests.
+    protected void runTestAtIndex(int testIndex) {
+        mTestIndex = testIndex;
+        
+        resetTestStatus();
+
+        if (testIndex == mTestList.size()) {
+            if (!mSingleTestMode) {
+                updateTestStatus("#DONE");
+            }
+            finished();
+            return;
+        }
+        String s = mTestList.elementAt(testIndex);
+        if (!mSingleTestMode)
+            updateTestStatus(s);
+        
+        Log.v(LOGTAG, "  Running test: "+s);
+        mWebView.loadUrl("file://"+s);
+        
+        if (!mSingleTestMode) {
+            // Create a timeout timer
+            Message m = mHandler.obtainMessage(MSG_TIMEOUT);
+            mHandler.sendMessageDelayed(m, mTimeoutInMillis);
+        }
+    }
+
+    // Dump the page
+    public void dump(boolean timeout, String webkitData) {
+        String currentTest = mTestList.elementAt(mTestIndex);
+        String resultFile = currentTest.substring(0, currentTest.lastIndexOf('.'));
+
+        // dumpAsText version can be directly compared to expected results
+        if (mDumpAsText) {
+            resultFile += "-results.txt";
+        } else {
+            resultFile += "-android-results.txt";
+        }
+
+        try {
+            FileOutputStream os = new FileOutputStream(resultFile);
+            if (timeout) {
+                Log.w("Layout test: Timeout", resultFile);
+                os.write(TIMEOUT_STR.getBytes());
+                os.write('\n');
+            }
+            if (mDumpTitleChanges)
+                os.write(mTitleChanges.toString().getBytes());
+            if (mDialogStrings != null)
+                os.write(mDialogStrings.toString().getBytes());
+            mDialogStrings = null;
+            os.write(webkitData.getBytes());
+            os.flush();
+            os.close();
+        } catch (FileNotFoundException ex) {
+            ex.printStackTrace();
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+
+        processResult(timeout, currentTest);
+        runTestAtIndex(mTestIndex + 1);
+    }
+
+    // Wrap up
+    public void failedCase(String file, String reason) {
+        Log.w("Layout test: ", file + " failed " + reason);
+        mResultRecorder.failed(file, reason);
+
+        String bugNumber = FileFilter.isKnownBug(file);
+        if (bugNumber != null) {
+            System.out.println("FAIL known:"+bugNumber+ " "+file+reason);
+            return;
+        }
+        if (FileFilter.ignoreResults(file)) {
+            return;
+        }
+        System.out.println("FAIL: "+file+reason);        
+    }
+
+    public void passedCase(String file) {
+        Log.v("Layout test:", file + " passed");
+        mResultRecorder.passed(file);
+
+        String bugNumber = FileFilter.isKnownBug(file);
+        if (bugNumber != null) {
+            System.out.println("Bug Fixed: "+bugNumber+ " "+file);
+            return;
+        }
+ 
+        if (FileFilter.ignoreResults(file)) {
+            System.out.println("Ignored test passed: "+file);
+            return;
+        }
+    }
+
+    public void nontextCase(String file, boolean has_expected_results) {
+        Log.v("Layout test:", file + " nontext");
+        mResultRecorder.nontext(file, has_expected_results);
+    }
+ 
+    public void setCallback(HTMLHostCallbackInterface callback) {
+        mCallback = callback;
+    }
+
+    public void processResult(boolean timeout, String test_path) {
+        Log.v(LOGTAG, "  Processing result: " + test_path);
+        // remove the extension
+        String short_file = test_path.substring(0, test_path.lastIndexOf('.'));
+        if (timeout) {
+            failedCase(test_path, "TIMEDOUT");
+            return;
+        }
+        // Only check results that we can check, ie dumpAsText results
+        String dumpFile = short_file + "-results.txt";
+        File f = new File(dumpFile);
+        if (f.exists()) {
+            try {
+                FileInputStream fr = new FileInputStream(short_file+"-results.txt");
+                FileInputStream fe = new FileInputStream(short_file+"-expected.txt");
+              
+                // If the length is different then they are different
+                int diff = fe.available() - fr.available();
+                if (diff > 1 || diff < 0) {
+                    failedCase(test_path, " different length");
+                    fr.close();
+                    fe.close();
+                    return;
+                }
+                byte[] br = new byte[fr.available()];
+                byte[] be = new byte[fe.available()];
+                fr.read(br);
+                fe.read(be);
+                boolean fail = false;
+                for (int i = 0; i < br.length; i++) {
+                    if (br[i] != be[i]) {
+                        failedCase(test_path, "  @offset: "+i);
+                        fr.close();
+                        fe.close();
+                        return;
+                    }
+                }
+                if (br.length != be.length && be[be.length-1] == '\n') {
+                    Log.d(LOGTAG, "Extra new line being ignore:" + test_path);
+                }
+                fr.close();
+                fe.close();
+                passedCase(test_path);
+            } catch (FileNotFoundException ex) {
+              // TODO do something here
+            } catch (IOException ex) {
+              // Failed on available() or read()
+            }
+            
+            return;
+        }
+        
+        File nontext_result = new File(short_file + "-android-results.txt");
+        if (nontext_result.exists()) {
+            // Check if the test has expected results.
+            File expected = new File(short_file + "-expected.txt");
+            nontextCase(test_path, expected.exists());
+        }
+    }
+    
+    public void finished() {
+        if (mCallback != null) {
+            mCallback.waitForFinish();
+        }
+
+        mFinishedRunning = true;
+        finish();
+    }
+    
+    // LayoutTestController Functions
+    public void dumpAsText() {
+        mDumpAsText = true;
+        if (mWebView != null) {
+            String url = mWebView.getUrl();
+            Log.v(LOGTAG, "dumpAsText called: "+url);
+        }
+    }
+
+    public void waitUntilDone() {
+        mWaitUntilDone = true;
+        String url = mWebView.getUrl();
+        Log.v(LOGTAG, "waitUntilDone called: " + url);
+    }
+    public void notifyDone() {
+        String url = mWebView.getUrl();
+        Log.v(LOGTAG, "notifyDone called: " + url);
+        if (mWaitUntilDone) {
+            mWaitUntilDone = false;
+            mChromeClient.onProgressChanged(mWebView, 100);
+        }
+    }
+    
+    public void display() {
+        mWebView.invalidate();
+    }
+
+    public void clearBackForwardList() {
+        mWebView.clearHistory();
+
+    }
+
+    public void dumpBackForwardList() {
+        //printf("\n============== Back Forward List ==============\n");
+        // mWebHistory
+        //printf("===============================================\n");
+
+    }
+
+    public void dumpChildFrameScrollPositions() {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void dumpEditingCallbacks() {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void dumpSelectionRect() {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void dumpTitleChanges() {
+        if (!mDumpTitleChanges) {
+            mTitleChanges = new StringBuffer();
+        }
+        mDumpTitleChanges = true;
+    }
+
+    public void keepWebHistory() {
+        if (!mKeepWebHistory) {
+            mWebHistory = new Vector();
+        }
+        mKeepWebHistory = true;
+    }
+
+    public void queueBackNavigation(int howfar) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void queueForwardNavigation(int howfar) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void queueLoad(String Url, String frameTarget) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void queueReload() {
+        mWebView.reload();
+    }
+
+    public void queueScript(String scriptToRunInCurrentContext) {
+        mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);     
+    }
+
+    public void repaintSweepHorizontally() {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setAcceptsEditing(boolean b) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setMainFrameIsFirstResponder(boolean b) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void setWindowIsKey(boolean b) {
+        // This is meant to show/hide the window. The best I can find
+        // is setEnabled()
+        mWebView.setEnabled(b);
+    }
+
+    public void testRepaint() {
+        mWebView.invalidate();
+    }
+
+    // Instrumentation calls this to find
+    // if the activity has finished running the layout tests
+    // TODO(fqian): need to sync on mFinisheRunning
+    public boolean hasFinishedRunning() {
+        return mFinishedRunning;
+    }
+    
+    private final WebChromeClient mChromeClient = new WebChromeClient() {
+        @Override
+        public void onProgressChanged(WebView view, int newProgress) {
+            if (newProgress == 100) {
+                if (!mSingleTestMode && !mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
+                    String url = mWebView.getUrl();
+                    Log.v(LOGTAG, "Finished: "+ url);
+                    mHandler.removeMessages(MSG_TIMEOUT);
+                    requestWebKitData();
+                } else {
+                    String url = mWebView.getUrl();
+                    if (mSingleTestMode) {
+                        Log.v(LOGTAG, "Single test mode: " + url);
+                    } else if (mTimedOut) {
+                        Log.v(LOGTAG, "Timed out before finishing: " + url);
+                    } else if (mWaitUntilDone) {
+                        Log.v(LOGTAG, "Waiting for notifyDone: " + url);
+                    } else if (mRequestedWebKitData) {
+                        Log.v(LOGTAG, "Requested webkit data ready: " + url);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onReceivedTitle(WebView view, String title) {
+            if (title.length() > 30)
+                title = "..."+title.substring(title.length()-30);
+            setTitle(title);
+            if (mDumpTitleChanges) {
+                mTitleChanges.append("TITLE CHANGED: ");
+                mTitleChanges.append(title);
+                mTitleChanges.append("\n");
+            }
+        }
+
+        @Override
+        public boolean onJsAlert(WebView view, String url, String message,
+                JsResult result) {
+            if (mDialogStrings == null) {
+                mDialogStrings = new StringBuffer();
+            }
+            mDialogStrings.append("ALERT: ");
+            mDialogStrings.append(message);
+            mDialogStrings.append('\n');
+            result.confirm();
+            return true;
+        }
+        
+        @Override
+        public boolean onJsConfirm(WebView view, String url, String message,
+                JsResult result) {
+            if (mDialogStrings == null) {
+                mDialogStrings = new StringBuffer();
+            }
+            mDialogStrings.append("CONFIRM: ");
+            mDialogStrings.append(message);
+            mDialogStrings.append('\n');
+            result.confirm();
+            return true;
+        }
+        
+        @Override
+        public boolean onJsPrompt(WebView view, String url, String message,
+                String defaultValue, JsPromptResult result) {
+            if (mDialogStrings == null) {
+                mDialogStrings = new StringBuffer();
+            }
+            mDialogStrings.append("PROMPT: ");
+            mDialogStrings.append(message);
+            mDialogStrings.append(", default text: ");
+            mDialogStrings.append(defaultValue);
+            mDialogStrings.append('\n');
+            result.confirm();
+            return true;
+        }
+    };
+    
+    private void resetTestStatus() {
+        mWaitUntilDone = false;
+        mDumpAsText = false;
+        mTimedOut = false;
+        mDumpTitleChanges = false;
+        mRequestedWebKitData = false;
+        mEventSender.resetMouse();
+    }
+    
+    private TestRecorder mResultRecorder;
+    private HTMLHostCallbackInterface mCallback = null;
+    private CallbackProxy mCallbackProxy;
+    
+    private WebView mWebView;
+    private WebViewEventSender mEventSender;
+    
+    private Vector<String> mTestList;
+    private int mTestIndex;
+
+    private int mTimeoutInMillis;
+    private String mTestPathPrefix;
+    private boolean mSingleTestMode;
+    
+    private AsyncHandler mHandler;
+    private boolean mFinishedRunning;
+
+    private boolean mTimedOut;
+    private boolean mRequestedWebKitData;
+    private boolean mDumpAsText;
+    private boolean mWaitUntilDone;
+    private boolean mDumpTitleChanges;
+    
+    private StringBuffer mTitleChanges;
+    private StringBuffer mDialogStrings;
+
+    private boolean mKeepWebHistory;
+    private Vector mWebHistory;
+
+    static final String TIMEOUT_STR = "**Test timeout";
+    
+    static final int MSG_TIMEOUT = 0;
+    static final int MSG_WEBKIT_DATA = 1;
+
+    static final String LOGTAG="DumpRenderTree";
+
+    static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
+    static final String LAYOUT_TESTS_LIST_FILE = "/sdcard/layout_tests_list.txt";
+    static final String TEST_STATUS_FILE = "/sdcard/running_test.txt";
+    
+    static final String RESUME_FROM_CRASH = "ResumeFromCrash";
+    static final String TEST_PATH_PREFIX = "TestPathPrefix";
+    static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
+    static final String SINGLE_TEST_MODE = "SingleTestMode";
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java
new file mode 100644
index 0000000..f610f5a
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+import android.app.Application;
+
+public class HTMLHostApp extends Application { 
+
+	public HTMLHostApp() {
+    }
+
+    public void onCreate() {
+    }
+
+    public void onTerminate() {
+    }
+	
+}
+
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java
new file mode 100644
index 0000000..60a2915
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+public interface HTMLHostCallbackInterface {
+    public void waitForFinish();
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
new file mode 100644
index 0000000..6166dd0
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+public interface LayoutTestController {
+
+	public void dumpAsText();
+	public void waitUntilDone();
+	public void notifyDone();
+	
+	// Force a redraw of the page
+	public void display();
+	// Used with pixel dumps of content
+	public void testRepaint();
+	
+	// If the page title changes, add the information to the output.
+	public void dumpTitleChanges();
+	public void dumpBackForwardList();
+	public void dumpChildFrameScrollPositions();
+	public void dumpEditingCallbacks();
+	
+	// Show/Hide window for window.onBlur() testing
+	public void setWindowIsKey(boolean b);
+	// Mac function, used to disable events going to the window
+	public void setMainFrameIsFirstResponder(boolean b);
+	
+	public void dumpSelectionRect();
+	
+	// invalidate and draw one line at a time of the web view.
+    public void repaintSweepHorizontally();
+    
+    // History testing functions
+    public void keepWebHistory();
+    public void clearBackForwardList();
+    // navigate after page load has finished
+    public void queueBackNavigation(int howfar);
+    public void queueForwardNavigation(int howfar);
+    
+    // Reload when the page load has finished
+    public void queueReload();
+    // Execute the provided script in current context when page load has finished.
+    public void queueScript(String scriptToRunInCurrentContext);
+    // Load the provided URL into the provided frame
+    public void queueLoad(String Url, String frameTarget);
+
+    public void setAcceptsEditing(boolean b);
+	
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
new file mode 100755
index 0000000..1f37405
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 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.dumprendertree;
+
+import junit.framework.TestSuite;
+import com.android.dumprendertree.LayoutTestsAutoTest;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import android.util.Log;
+import android.content.Intent;
+import android.os.Bundle;
+
+
+/**
+ * Instrumentation Test Runner for all MediaPlayer tests.
+ * 
+ * Running all tests:
+ *
+ * adb shell am instrument \
+ *   -w com.android.dumprendertree.LayoutTestsAutoRunner
+ */
+
+public class LayoutTestsAutoRunner extends InstrumentationTestRunner {
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(LayoutTestsAutoTest.class);
+        return suite;
+    }
+
+    @Override
+    public ClassLoader getLoader() {
+        return LayoutTestsAutoRunner.class.getClassLoader();
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        String path = (String) icicle.get("path");
+        LayoutTestsAutoTest.setLayoutTestDir(path);
+        String timeout_str = (String) icicle.get("timeout");
+        int timeout = 0;  // default value
+        if (timeout_str != null) {
+            try {
+                timeout = Integer.parseInt(timeout_str);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        LayoutTestsAutoTest.setTimeoutInMillis(timeout);
+    }
+}
+
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
new file mode 100644
index 0000000..3e65f0358
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008 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.dumprendertree;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+
+import android.util.Log;
+import android.view.KeyEvent;
+
+import android.os.Bundle;
+import android.os.Message;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.dumprendertree.HTMLHostActivity;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase<Menu> {
+
+    private final static String LOGTAG = "LayoutTests";
+    private final static int DEFAULT_TIMEOUT_IN_MILLIS = 6000;
+    private static String layoutTestDir = null;
+    private static int mTimeoutInMillis = 0;
+    
+    public LayoutTestsAutoTest() {
+      super("com.android.dumprendertree", Menu.class);
+    }
+
+    // This function writes the result of the layout test to
+    // Am status so that it can be picked up from a script.
+    public void passOrFailCallback(String file, boolean result) {
+      Instrumentation inst = getInstrumentation();
+      Bundle bundle = new Bundle();
+      bundle.putBoolean(file, result);
+      inst.sendStatus(0, bundle);
+    }
+
+    public static void setTimeoutInMillis(int millis) {
+        mTimeoutInMillis = (millis > 0) ? millis : DEFAULT_TIMEOUT_IN_MILLIS;
+    }
+
+    public static void setLayoutTestDir(String name) {
+        if (name == null)
+            throw new AssertionError("Layout test directory cannot be null.");
+      layoutTestDir = HTMLHostActivity.LAYOUT_TESTS_ROOT + name;
+      Log.v("LayoutTestsAutoTest", " Only running the layout tests : " + layoutTestDir);
+    }
+
+    // Invokes running of layout tests
+    // and waits till it has finished running.
+    public void executeLayoutTests(boolean resume) {
+      Instrumentation inst = getInstrumentation();
+      
+      {
+          Activity activity = getActivity();
+          Intent intent = new Intent();
+          intent.setClass(activity, HTMLHostActivity.class);
+          intent.putExtra(HTMLHostActivity.RESUME_FROM_CRASH, resume);
+          intent.putExtra(HTMLHostActivity.SINGLE_TEST_MODE, false);
+          intent.putExtra(HTMLHostActivity.TEST_PATH_PREFIX, layoutTestDir);
+          intent.putExtra(HTMLHostActivity.TIMEOUT_IN_MILLIS, mTimeoutInMillis);
+          activity.startActivity(intent);
+      }
+      
+      ActivityMonitor htmlHostActivityMonitor =
+          inst.addMonitor("com.android.dumprendertree.HTMLHostActivity", null, false);
+
+      HTMLHostActivity activity =
+          (HTMLHostActivity) htmlHostActivityMonitor.waitForActivity();
+
+      while (!activity.hasFinishedRunning()) {
+          // Poll every 5 seconds to determine if the layout
+          // tests have finished running
+          try {Thread.sleep(5000); } catch(Exception e){}
+      }
+
+      // Wait few more seconds so that results are
+      // flushed to the /sdcard
+      try {Thread.sleep(5000); } catch(Exception e){}
+
+      // Clean up the HTMLHostActivity activity
+      activity.finish();
+    }
+    
+    public void generateTestList() {
+        try {
+            File tests_list = new File(HTMLHostActivity.LAYOUT_TESTS_LIST_FILE);
+            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
+            findTestsRecursively(bos, layoutTestDir);
+            bos.flush();
+            bos.close();
+       } catch (Exception e) {
+           Log.e(LOGTAG, "Error when creating test list: " + e.getMessage());
+       }
+    }
+
+    private void findTestsRecursively(BufferedOutputStream bos, String dir) throws IOException {
+         Log.v(LOGTAG, "Searching tests under " + dir);
+         
+         File d = new File(dir);
+         if (!d.isDirectory()) {
+             throw new AssertionError("A directory expected, but got " + dir);
+         }
+         
+         String[] files = d.list();
+         for (int i = 0; i < files.length; i++) {
+             String s = dir + "/" + files[i];
+             if (FileFilter.ignoreTest(s)) {
+                 Log.v(LOGTAG, "  Ignoring: " + s);
+                 continue;
+             }
+             if (s.toLowerCase().endsWith(".html") 
+                 || s.toLowerCase().endsWith(".xml")) {
+                 bos.write(s.getBytes());
+                 bos.write('\n');
+                 continue;
+             }
+             
+             File f = new File(s);
+             if (f.isDirectory()) {
+                 findTestsRecursively(bos, s);
+                 continue;
+             }
+             
+             Log.v(LOGTAG, "Skipping " + s);
+        }
+    }
+    
+    // Running all the layout tests at once sometimes
+    // causes the dumprendertree to run out of memory.
+    // So, additional tests are added to run the tests
+    // in chunks.
+    public void startLayoutTests() {
+        try {
+            File tests_list = new File(HTMLHostActivity.LAYOUT_TESTS_LIST_FILE);
+            if (!tests_list.exists())
+              generateTestList();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        
+        executeLayoutTests(false);
+    }
+
+    public void resumeLayoutTests() {
+        executeLayoutTests(true);
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
new file mode 100644
index 0000000..de0da61
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.io.File;
+
+public class Menu extends FileList {
+    
+    public void onCreate(Bundle icicle) 
+    {
+        super.onCreate(icicle);
+    }
+    
+    boolean fileFilter(File f) {
+    	if (f.getName().startsWith("."))
+    		return false;
+    	if (f.getName().equalsIgnoreCase("resources"))
+    		return false;
+    	if (f.isDirectory())
+    		return true;
+    	if (f.getPath().toLowerCase().endsWith("ml"))
+    		return true;
+    	return false;
+    }
+    
+    void processFile(String filename, boolean selection)
+    {
+        Intent result = new Intent();
+        result.setClass(this, HTMLHostActivity.class);
+        result.putExtra(HTMLHostActivity.RESUME_FROM_CRASH, false);
+        result.putExtra(HTMLHostActivity.SINGLE_TEST_MODE, true);
+        result.putExtra(HTMLHostActivity.TEST_PATH_PREFIX, filename);
+        result.putExtra(HTMLHostActivity.TIMEOUT_IN_MILLIS, 8000);
+        startActivity(result);
+    }
+   
+}
+
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
new file mode 100644
index 0000000..eea6346
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007 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.dumprendertree;
+
+import android.webkit.WebView;
+import android.view.KeyEvent;
+import android.util.*;
+
+import java.util.Arrays;
+
+public class WebViewEventSender implements EventSender {
+	
+	WebViewEventSender(WebView webView) {
+		mWebView = webView;
+	}
+	
+	public void resetMouse() {
+		mouseX = mouseY = 0;
+	}
+
+	public void enableDOMUIEventLogging(int DOMNode) {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void fireKeyboardEventsToElement(int DOMNode) {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void keyDown(String character, String[] withModifiers) {
+        Log.e("EventSender", "KeyDown: " + character + "("
+                + character.getBytes()[0] + ") Modifiers: "
+                + Arrays.toString(withModifiers));
+        KeyEvent modifier = null;
+        if (withModifiers != null && withModifiers.length > 0) {
+            for (int i = 0; i < withModifiers.length; i++) {
+                int keyCode = modifierMapper(withModifiers[i]);
+                modifier = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+                mWebView.onKeyDown(modifier.getKeyCode(), modifier);
+            }
+        }
+        int keyCode = keyMapper(character.toLowerCase().toCharArray()[0]);
+        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+        mWebView.onKeyDown(event.getKeyCode(), event);
+
+    }
+	
+	public void keyDown(String character) {
+        keyDown(character, null);
+	}
+
+	public void leapForward(int milliseconds) {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void mouseClick() {
+		mouseDown();
+		mouseUp();
+	}
+
+	public void mouseDown() {
+          /*  KeyEvent event = new KeyEvent(
+                KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
+            mWebView.onKeyDown(event.getKeyCode(), event); */
+	}
+
+	public void mouseMoveTo(int X, int Y) {
+		if (X > mouseX) {
+                    KeyEvent event = new KeyEvent(
+                        KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
+                    mWebView.onKeyDown(event.getKeyCode(), event);
+                    mWebView.onKeyUp(event.getKeyCode(), event);
+		} else if ( X < mouseX ) {
+                    KeyEvent event = new KeyEvent(
+                        KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT);
+                    mWebView.onKeyDown(event.getKeyCode(), event);
+                    mWebView.onKeyUp(event.getKeyCode(), event);
+		}
+		if (Y > mouseY) {
+                    KeyEvent event = new KeyEvent(
+                        KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN);
+                    mWebView.onKeyDown(event.getKeyCode(), event);
+                    mWebView.onKeyUp(event.getKeyCode(), event);
+		} else if (Y < mouseY ) {
+                    KeyEvent event = new KeyEvent(
+                        KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP);
+                    mWebView.onKeyDown(event.getKeyCode(), event);
+                    mWebView.onKeyUp(event.getKeyCode(), event);
+		}
+		mouseX= X;
+		mouseY= Y;
+	
+	}
+
+	public void mouseUp() {
+        /*    KeyEvent event = new KeyEvent(
+                KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER);
+            mWebView.onKeyDown(event.getKeyCode(), event);*/
+
+	}
+	
+	// Assumes lowercase chars, case needs to be
+	// handled by calling function.
+	static int keyMapper(char c) {
+		// handle numbers
+		if (c >= '0' && c<= '9') {
+			int offset = c - '0';
+			return KeyEvent.KEYCODE_0 + offset;
+		}
+
+		// handle characters
+		if (c >= 'a' && c <= 'z') {
+			int offset = c - 'a';
+			return KeyEvent.KEYCODE_A + offset;
+		}
+
+		// handle all others
+		switch (c) {
+		case '*':
+			return KeyEvent.KEYCODE_STAR;
+		case '#':
+			return KeyEvent.KEYCODE_POUND;
+		case ',':
+			return KeyEvent.KEYCODE_COMMA;
+		case '.':
+			return KeyEvent.KEYCODE_PERIOD;
+		case '\t':
+			return KeyEvent.KEYCODE_TAB;
+		case ' ':
+			return KeyEvent.KEYCODE_SPACE;
+		case '\n':
+			return KeyEvent.KEYCODE_ENTER;
+		case '\b':
+        case 0x7F:
+			return KeyEvent.KEYCODE_DEL;
+		case '~':
+			return KeyEvent.KEYCODE_GRAVE;
+		case '-':
+			return KeyEvent.KEYCODE_MINUS;
+		case '=':
+			return KeyEvent.KEYCODE_EQUALS;
+		case '(':
+			return KeyEvent.KEYCODE_LEFT_BRACKET;
+		case ')':
+			return KeyEvent.KEYCODE_RIGHT_BRACKET;
+		case '\\':
+			return KeyEvent.KEYCODE_BACKSLASH;
+		case ';':
+			return KeyEvent.KEYCODE_SEMICOLON;
+		case '\'':
+			return KeyEvent.KEYCODE_APOSTROPHE;
+		case '/':
+			return KeyEvent.KEYCODE_SLASH;
+		default:
+			break;
+		}
+
+		return c;
+	}
+	
+	static int modifierMapper(String modifier) {
+		if (modifier.equals("ctrlKey")) {
+			return KeyEvent.KEYCODE_ALT_LEFT;
+		} else if (modifier.equals("shiftKey")) {
+			return KeyEvent.KEYCODE_SHIFT_LEFT;
+		} else if (modifier.equals("altKey")) {
+			return KeyEvent.KEYCODE_SYM;
+		} else if (modifier.equals("metaKey")) {
+			return KeyEvent.KEYCODE_UNKNOWN;
+		}
+		return KeyEvent.KEYCODE_UNKNOWN;
+	}
+	
+    private WebView mWebView = null;
+    private int mouseX;
+    private int mouseY;
+
+}
diff --git a/tests/FrameworkTest/Android.mk b/tests/FrameworkTest/Android.mk
new file mode 100644
index 0000000..61cdbfa
--- /dev/null
+++ b/tests/FrameworkTest/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := FrameworkTest
+
+include $(BUILD_PACKAGE)
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/FrameworkTest/AndroidManifest.xml b/tests/FrameworkTest/AndroidManifest.xml
new file mode 100644
index 0000000..c70302b
--- /dev/null
+++ b/tests/FrameworkTest/AndroidManifest.xml
@@ -0,0 +1,952 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.frameworktest">
+
+    <uses-permission android:name="android.permission.READ_CONTACTS" />
+    <uses-permission android:name="android.permission.HARDWARE_TEST" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+
+    <application android:theme="@style/Theme">
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name=".FrameworkTestApplication" android:label="FrameworkTestApplication">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".performance.InvalidateCycle" android:label="InvalidateCycle">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".focus.DescendantFocusability" android:label="DescendantFocusability">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".focus.FocusAfterRemoval" android:label="FocusAfterRemoval">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".focus.RequestFocus" android:label="RequestFocus">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />V
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".focus.ListOfButtons" android:label="ListOfButtons">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".focus.LinearLayoutGrid" android:label="LinearLayoutGrid">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".focus.ListOfEditTexts" android:label="ListOfEditTexts">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".focus.ListOfInternalSelectionViews" android:label="ListOfInternalSelectionViews">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>                        
+        </activity>
+
+        <activity android:name=".focus.ListWithFooterViewAndNewLabels" android:label="FocusListWithFooter">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".focus.ListWithMailMessages" android:label="ListWithMailMessages">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".focus.HorizontalFocusSearch" android:label="HorizontalFocusSearch">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".focus.VerticalFocusSearch" android:label="VerticalFocusSearch">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".focus.AdjacentVerticalRectLists" android:label="AdjacentVerticalRectLists">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".focus.GoneParentFocusedChild" android:label="GoneParentFocusedChild">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.frame.FrameLayoutGravity" android:label="FrameLayoutGravity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.frame.FrameLayoutMargin" android:label="FrameLayoutMargin">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.BaselineAlignmentCenterGravity" android:label="BaselineAlignmentCenterGravity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.BaselineButtons" android:label="BaselineButtons">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.FillInWrap" android:label="FillInWrap">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.BaselineAlignmentZeroWidthAndWeight" android:label="Baseline0WidthAndWeight">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.HorizontalOrientationVerticalAlignment" android:label="HorizontalOrientationVerticalAlignment">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.LLEditTextThenButton" android:label="LLEditTextThenButton">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".layout.linear.LLOfButtons1" android:label="LLOfButtons1">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.LinearLayoutEditTexts" android:label="LinearLayoutEditTexts">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.LLOfButtons2" android:label="LLOfButtons2">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.LLOfTwoFocusableInTouchMode" android:label="LLOfTwoFocusableInTouchMode">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".layout.linear.Weight" android:label="Weight">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.linear.WeightSum" android:label="WeightSum">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.AdjacentListsWithAdjacentISVsInside" android:label="AdjacentListsWithAdjacentISVsInside">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListDividers" android:label="ListDividers">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListViewHeight" android:label="ListViewHeight">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.table.FixedWidth" android:label="CellFixedWidth">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.table.Weight" android:label="CellWeight">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.table.HorizontalGravity" android:label="CellHorizontalGravity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.table.VerticalGravity" android:label="CellVerticalGravity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.table.AddColumn" android:label="AddColumnInTable">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".layout.table.CellSpan" android:label="CellSpan">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".scroll.ButtonAboveTallInternalSelectionView" android:label="ButtonAboveTallInternalSelectionView">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".scroll.ButtonsWithTallTextViewInBetween" android:label="scrollButtonsWithTallTextViewInBetween">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".scroll.RequestRectangleVisible" android:label="ScrollToChildRect">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".scroll.RequestRectangleVisibleWithInternalScroll" android:label="ScrollToChildRectWithInternalScroll">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".scroll.ScrollViewButtonsAndLabels" android:label="ScrollViewButtonsAndLabels">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".scroll.ShortButtons" android:label="scrollShortButtons">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".scroll.TallTextAboveButton" android:label="scrollTallTextAboveButton">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.Include" android:label="IncludeTag">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.Merge" android:label="MergeTag">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.StubbedView" android:label="ViewStub">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.RunQueue" android:label="RunQueue">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.Visibility" android:label="Visibility">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.BigCache" android:label="BigCache">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.ZeroSized" android:label="ZeroSized">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.Disabled" android:label="Disabled">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.PopupWindowVisibility" android:label="PopupWindowVisibility">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".view.PreDrawListener" android:label="PreDrawListener">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.GlobalFocusChange" android:label="GlobalFocusChange">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListSetSelection" android:label="ListSetSelection">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListSimple" android:label="ListSimple">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListFilter" android:label="ListFilter">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".listview.ListScrollListener" android:label="ListScrollListener">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListThrasher" android:label="ListThrasher">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".listview.ListTakeFocusFromSide" android:label="ListTakeFocusFromSide">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".listview.ListBottomGravity" android:label="ListBottomGravity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".listview.ListBottomGravityMany" android:label="ListBottomGravityMany">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+
+        <activity android:name=".listview.ListButtonsDiagonalAcrossItems" android:label="ListButtonsDiagonalAcrossItems">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListTopGravity" android:label="ListTopGravity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".listview.ListTopGravityMany" android:label="ListTopGravityMany">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".listview.ListEndingWithMultipleSeparators" android:label="ListEndingWithMultipleSeparators">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>                        
+        </activity>
+
+        <activity android:name=".listview.ListGetSelectedView" android:label="ListGetSelectedView">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListInHorizontal" android:label="ListInHorizontal">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListInVertical" android:label="ListInVertical">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListInterleaveFocusables" android:label="ListInterleaveFocusables">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+             <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+         </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListOfItemsShorterThanScreen" android:label="ListOfItemsShorterThanScreen">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListOfItemsTallerThanScreen" android:label="ListOfItemsTallerThanScreen">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListOfThinItems" android:label="ListOfThinItems">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>                        
+        </activity>
+
+        <activity android:name=".listview.ListOfShortTallShort" android:label="ListOfShortTallShort">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListOfShortShortTallShortShort" android:label="ListOfShortShortTallShortShort">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListWithOffScreenNextSelectable" android:label="ListWithOffScreenNextSelectable">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>                                    
+        </activity>
+
+        <activity android:name=".listview.ListWithFirstScreenUnSelectable" android:label="ListWithFirstScreenUnSelectable">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+
+        <activity android:name=".listview.ListWithSeparators" android:label="ListWithSeparators">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListWithHeaders" android:label="ListWithHeaders">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListWithEditTextHeader" android:label="ListWithEditTextHeader">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+
+        <activity android:name=".listview.ListWithNoFadingEdge" android:label="ListWithNoFadingEdge">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListWithScreenOfNoSelectables" android:label="ListWithScreenOfNoSelectables">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListItemFocusablesFarApart" android:label="ListItemFocusablesFarApart">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListItemFocusableAboveUnfocusable" android:label="ListItemFocusableAboveUnfocusable">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListItemFocusablesClose" android:label="ListItemFocusablesClose">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListLastItemPartiallyVisible" android:label="ListLastItemPartiallyVisible">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListItemsExpandOnSelection" android:label="ListItemsExpandOnSelection">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListWithOnItemSelectedAction" android:label="ListWithOnItemSelectedAction">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+
+        <activity android:name=".listview.ListItemISVAndButton" android:label="ListItemISVAndButton">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListOfTouchables" android:label="ListOfTouchables">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListRecyclerProfiling" android:label="ListRecyclerProfiling">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListHeterogeneous" android:label="ListHeterogeneous">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListHorizontalFocusWithinItemWins" android:label="ListHorizontalFocusWithinItemWins">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>            
+        </activity>
+       
+	    <activity android:name=".listview.ListManagedCursor" android:label="ListManagedCursor">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+       
+	    <activity android:name=".listview.ListWithEmptyView" android:label="ListWithEmptyView">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".gridview.GridInHorizontal" android:label="GridInHorizontal">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".gridview.GridPadding" android:label="GridPadding">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridInVertical" android:label="GridInVertical">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridScrollListener" android:label="GridScrollListener">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+         <activity android:name=".gridview.GridThrasher" android:label="GridThrasher">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridSimple" android:label="GridSimple">
+           <intent-filter>
+               <action android:name="android.intent.action.MAIN" />
+               <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+           </intent-filter>
+       </activity>
+
+        <activity android:name=".gridview.GridDelete" android:label="GridDelete">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+         <activity android:name=".gridview.GridSetSelection" android:label="GridSetSelection">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridSetSelectionMany" android:label="GridSetSelectionMany">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridSetSelectionStackFromBottom" android:label="GridSetSelectionStackFromBottom">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridSetSelectionStackFromBottomMany" android:label="GridSetSelectionStackFromBottomMany">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridStackFromBottom" android:label="GridStackFromBottom">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridStackFromBottomMany" android:label="GridStackFromBottomMany">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".gridview.GridVerticalSpacing" android:label="GridVerticalSpacing">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".gridview.GridVerticalSpacingStackFromBottom" android:label="GridVerticalSpacingStackFromBottom">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".gridview.GridSingleColumn" android:label="GridSingleColumn">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".menus.ListContextMenu" android:label="ListContextMenu">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.ViewGroupChildren" android:label="ViewGroup Children">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".view.RemoteViewsActivity" android:label="RemoteViewsActicity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".drawable.BitmapDrawable" android:label="BitmapDrawable">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".drawable.DrawableBgMinSize" android:label="DrawableBgMinSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".drawable.MutateDrawable" android:label="MutateDrawable">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".activity.TranslucentFancyActivity" android:label="TranslucentFancyActivity">
+           <intent-filter>
+               <action android:name="android.intent.action.MAIN" />
+               <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+           </intent-filter>
+       </activity>
+
+        <activity android:name=".view.Longpress" android:label="Longpress">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".expandablelistview.ExpandableListWithHeaders" android:label="ExpandableListWithHeaders">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".listview.ListWithDisappearingItemBug" android:label="ListWithDisappearingItemBug">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".menus.MenuWith1Item" android:label="MenuWith1Item">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".menus.MenuLayoutPortrait" android:label="MenuLayoutPortrait"
+                android:screenOrientation="portrait">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".menus.MenuLayoutLandscape" android:label="MenuLayoutLandscape"
+                android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".expandablelistview.InflatedExpandableListView" android:label="ExpandableListView Inflated">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".expandablelistview.ExpandableListSimple" android:label="ExpandableListSimple">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".settings.RingtonePickerActivityLauncher" android:label="RingtonePickerActivityLauncher">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".settings.BrightnessLimit" android:label="BrightnessLimit">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name="android.widget.AutoCompleteTextViewSimple" 
+                  android:label="AutoCompleteTextViewSimple">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/tests/FrameworkTest/README b/tests/FrameworkTest/README
new file mode 100644
index 0000000..d6d0042
--- /dev/null
+++ b/tests/FrameworkTest/README
@@ -0,0 +1,8 @@
+FrameworkTestApplication should hold snippets of functionality that are
+helpful for testing the UI framework code, but not appropriate for
+sample code.  For instance, a layout contrived to exercise an edge case
+of scrolling behavior.
+
+InstrumentationTestCases should be added under tests and added to the
+list of tests in FrameworkInstrumentationTestRunner.
+
diff --git a/tests/FrameworkTest/res/drawable/big_drawable_background.9.png b/tests/FrameworkTest/res/drawable/big_drawable_background.9.png
new file mode 100644
index 0000000..aded635
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/big_drawable_background.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/bitmap_drawable.xml b/tests/FrameworkTest/res/drawable/bitmap_drawable.xml
new file mode 100644
index 0000000..35673ec
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/bitmap_drawable.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/sym_now_playing_pause_1"
+    android:gravity="top|right" />
diff --git a/tests/FrameworkTest/res/drawable/black_square.png b/tests/FrameworkTest/res/drawable/black_square.png
new file mode 100644
index 0000000..1bfe0a2
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/black_square.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png b/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png
new file mode 100644
index 0000000..1fcbeb1
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/box.xml b/tests/FrameworkTest/res/drawable/box.xml
new file mode 100644
index 0000000..6849bd34
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/box.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/drawable/box.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#00000000"/>
+    <stroke android:width="1dp" color="#ff000000"/>
+    <padding android:left="1dp" android:top="1dp"
+        android:right="1dp" android:bottom="1dp" />
+</shape>
diff --git a/tests/FrameworkTest/res/drawable/drawable_background.9.png b/tests/FrameworkTest/res/drawable/drawable_background.9.png
new file mode 100644
index 0000000..1337ba9
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/drawable_background.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png
new file mode 100644
index 0000000..2f19d08
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png
new file mode 100644
index 0000000..f945a81
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png
new file mode 100644
index 0000000..da9361a
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/layout/add_column_in_table.xml b/tests/FrameworkTest/res/layout/add_column_in_table.xml
new file mode 100644
index 0000000..62c27f3
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/add_column_in_table.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <TableLayout android:id="@+id/table"
+        android:layout_width="fill_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1.0">
+
+        <TableRow>
+            <TextView
+              android:text="@string/table_layout_a"
+                android:padding="3dip" />
+            <TextView
+                android:text="@string/table_layout_b"
+                android:padding="3dip" />
+            <TextView
+                android:text="@string/table_layout_c"
+                android:padding="3dip" />
+        </TableRow>
+
+    </TableLayout>
+
+    <Button android:id="@+id/add_row_button"
+        android:text="@string/add_row_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/autocompletetextview_simple.xml b/tests/FrameworkTest/res/layout/autocompletetextview_simple.xml
new file mode 100644
index 0000000..d408a86
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/autocompletetextview_simple.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2008, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <AutoCompleteTextView
+        android:id="@+id/autocompletetextview1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:inputType="text|textAutoComplete"
+        android:completionThreshold="1" />
+        />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/baseline_0width_and_weight.xml b/tests/FrameworkTest/res/layout/baseline_0width_and_weight.xml
new file mode 100644
index 0000000..83f3fcb
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/baseline_0width_and_weight.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+*
+**
+** Copyright 2008, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <LinearLayout android:id="@+id/layout"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:visibility="gone">
+        <com.android.frameworktest.layout.linear.ExceptionTextView
+             android:id="@+id/routeToField"
+             android:textSize="16sp"
+             android:layout_width="0dip"
+             android:layout_weight="1"
+             android:layout_height="wrap_content"
+             android:lines="2"
+             android:autoText="false"
+             android:capitalize="none"
+             android:maxLines="1" />
+         <Button
+             android:layout_height="wrap_content"
+             android:layout_width="wrap_content"
+             android:layout_gravity="fill_vertical"
+             android:text="@string/side_button_label" />
+    </LinearLayout>
+    <Button android:id="@+id/show"
+         android:layout_height="wrap_content"
+         android:layout_width="wrap_content"
+         android:text="@string/show" />
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/baseline_buttons.xml b/tests/FrameworkTest/res/layout/baseline_buttons.xml
new file mode 100644
index 0000000..ae942017
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/baseline_buttons.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+*
+**
+** Copyright 2008, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:id="@+id/layout"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal">
+
+    <TextView android:id="@+id/currenttime"
+    	android:text="@string/time"
+        android:textSize="12sp"
+        android:textStyle="bold"
+        android:layout_gravity="bottom"
+        android:layout_weight="1"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content" />
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:gravity="center">
+
+        <ImageButton android:id="@+id/prev"
+            android:src="@drawable/sym_now_playing_skip_backward_1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <ImageButton android:id="@+id/pause"
+            android:src="@drawable/sym_now_playing_pause_1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <ImageButton android:id="@+id/next"
+            android:src="@drawable/sym_now_playing_skip_forward_1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+    </LinearLayout>
+
+    <TextView android:id="@+id/totaltime"
+        android:textSize="12sp"
+        android:textStyle="bold"
+        android:gravity="right"
+        android:text="@string/time"
+        android:layout_gravity="bottom"
+        android:layout_weight="1"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/baseline_center_gravity.xml b/tests/FrameworkTest/res/layout/baseline_center_gravity.xml
new file mode 100644
index 0000000..9793ab4
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/baseline_center_gravity.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+*
+**
+** Copyright 2008, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+    <Button android:id="@+id/button1"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/side_button_label" />
+    <Button android:id="@+id/button2"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/side_button_label" />
+    <Button android:id="@+id/button3"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:layout_gravity="center"
+        android:text="@string/side_button_label" />
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/brightness_limit.xml b/tests/FrameworkTest/res/layout/brightness_limit.xml
new file mode 100644
index 0000000..46e5767
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/brightness_limit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<!-- Tries to set brightness to 0. See corresponding Java code. -->
+
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/go"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="@string/go"/>
+
diff --git a/tests/FrameworkTest/res/layout/descendant_focusability.xml b/tests/FrameworkTest/res/layout/descendant_focusability.xml
new file mode 100644
index 0000000..6a30d50d
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/descendant_focusability.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+        >
+
+    <LinearLayout
+        android:id="@+id/beforeDescendants"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:descendantFocusability="beforeDescendants"
+            >
+        <Button
+          android:layout_width="fill_parent"
+          android:layout_height="wrap_content"
+                />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/afterDescendants"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:descendantFocusability="afterDescendants"
+            >
+        <Button
+          android:layout_width="fill_parent"
+          android:layout_height="wrap_content"
+                />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/blocksDescendants"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:descendantFocusability="blocksDescendants"
+            >
+        <Button
+          android:layout_width="fill_parent"
+          android:layout_height="wrap_content"
+                />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/disabled.xml b/tests/FrameworkTest/res/layout/disabled.xml
new file mode 100644
index 0000000..ed7ff06
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/disabled.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<!-- Demonstrates changing view visibility. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/clickableParent"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <Button android:id="@+id/disabledButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/disabled_button"/>
+
+    <Button android:id="@+id/disabledButtonA"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/disabled_button"/>
+        
+    <Button android:id="@+id/disabledButtonB"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/disabled_button"/>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/drawable_background_minimum_size.xml b/tests/FrameworkTest/res/layout/drawable_background_minimum_size.xml
new file mode 100644
index 0000000..ea0cbfa
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/drawable_background_minimum_size.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+    
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        
+        <Button
+            android:id="@+id/change_backgrounds"
+            android:text="@string/change_backgrounds"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <!-- Different views and layouts that should initially be small but still contain
+             some content (hence the minimal text inside each of the layouts).  Each of these
+             will each be tested to make sure they expand to at least the minimum size
+             recommended by different backgrounds -->
+             
+        <TextView
+            android:id="@+id/text_view"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/minimal_text" />
+                
+        <LinearLayout
+            android:id="@+id/linear_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/minimal_text" />
+                
+        </LinearLayout>
+    
+        <RelativeLayout
+            android:id="@+id/relative_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/minimal_text" />
+                
+        </RelativeLayout>
+    
+        <FrameLayout
+            android:id="@+id/frame_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/minimal_text" />
+                
+        </FrameLayout>
+    
+        <AbsoluteLayout
+            android:id="@+id/absolute_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/minimal_text" />
+                
+        </AbsoluteLayout>
+    
+    </LinearLayout>
+
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/fill_in_wrap.xml b/tests/FrameworkTest/res/layout/fill_in_wrap.xml
new file mode 100644
index 0000000..b61fd30
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/fill_in_wrap.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:orientation="horizontal"
+    android:baselineAligned="false"
+    android:gravity="center_vertical">
+
+    <Button
+        android:layout_width="100dip"
+        android:layout_height="wrap_content"
+        android:gravity="left|center_vertical"
+    />
+
+    <LinearLayout android:id="@+id/layout"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="0dip"
+        android:paddingRight="0dip"
+        android:paddingTop="2dip"
+        android:paddingBottom="2dip"    
+        android:orientation="horizontal"
+        android:baselineAligned="false"
+        android:addStatesFromChildren="true"
+        android:background="@android:drawable/edit_text"
+        android:gravity="center_vertical">
+
+        <EditText android:id="@+id/data"
+            android:layout_width="0dip"
+            android:layout_weight="1"
+            android:layout_height="fill_parent"
+            android:layout_marginLeft="8dip"
+            android:paddingBottom="4dip"
+            android:layout_gravity="center_vertical"
+            android:background="@null"
+        />
+
+        <ImageButton
+            style="@android:style/Widget.Button.Inset"
+            android:src="@android:drawable/ic_delete"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="2dip"
+            android:gravity="center"
+        />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/focus_after_removal.xml b/tests/FrameworkTest/res/layout/focus_after_removal.xml
new file mode 100644
index 0000000..7cf6cbe
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/focus_after_removal.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout android:id="@+id/leftLayout"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <Button android:id="@+id/topLeftButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="3dip"
+            android:text="@string/left_top" />
+        <Button android:id="@+id/bottomLeftButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="3dip"
+            android:text="@string/left_bottom" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <Button android:id="@+id/topRightButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="3dip"
+            android:text="@string/right_top" />
+        <Button android:id="@+id/bottomRightButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="3dip"
+            android:text="@string/right_bottom" />
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/focus_listener.xml b/tests/FrameworkTest/res/layout/focus_listener.xml
new file mode 100644
index 0000000..a838205
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/focus_listener.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <Button android:id="@+id/left"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="3dip"
+        android:text="@string/left_top" />
+
+    <Button android:id="@+id/right"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="3dip"
+        android:text="@string/left_bottom" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/framelayout_gravity.xml b/tests/FrameworkTest/res/layout/framelayout_gravity.xml
new file mode 100644
index 0000000..ce48825
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/framelayout_gravity.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parent"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <Button android:id="@+id/left"
+        android:layout_gravity="left"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/right"
+        android:layout_gravity="right"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/center_horizontal"
+        android:layout_gravity="center_horizontal"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/left_center_vertical"
+        android:layout_gravity="center_vertical|left"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/right_center_vertical"
+        android:layout_gravity="center_vertical|right"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/center"
+        android:layout_gravity="center"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/left_bottom"
+        android:layout_gravity="bottom|left"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/right_bottom"
+        android:layout_gravity="bottom|right"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/center_horizontal_bottom"
+        android:layout_gravity="bottom|center_horizontal"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</FrameLayout>
diff --git a/tests/FrameworkTest/res/layout/framelayout_margin.xml b/tests/FrameworkTest/res/layout/framelayout_margin.xml
new file mode 100644
index 0000000..1e14899
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/framelayout_margin.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parent"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <Button android:id="@+id/left"
+        android:layout_gravity="left"
+        android:layout_marginLeft="12dip"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/right"
+        android:layout_gravity="right"
+        android:layout_marginRight="12dip"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/top"
+        android:layout_gravity="top|center_horizontal"
+        android:layout_marginTop="12dip"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/bottom"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginBottom="12dip"
+        android:text="@string/view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</FrameLayout>
diff --git a/tests/FrameworkTest/res/layout/grid_in_horizontal.xml b/tests/FrameworkTest/res/layout/grid_in_horizontal.xml
new file mode 100644
index 0000000..835dce3
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_in_horizontal.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:orientation="horizontal"
+	android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+	
+	<GridView android:id="@+id/grid"
+	    android:layout_width="0dip" 
+	    android:layout_height="fill_parent"
+	    android:layout_weight="1"
+	    android:padding="10dip"
+	    android:verticalSpacing="10dp"    
+	    android:horizontalSpacing="10dp"
+	    android:numColumns="auto_fit"
+	    android:columnWidth="60dp"
+	    android:stretchMode="columnWidth" />
+	    
+    <ImageButton
+        android:src="@drawable/sym_now_playing_pause_1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+    	
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/grid_in_vertical.xml b/tests/FrameworkTest/res/layout/grid_in_vertical.xml
new file mode 100644
index 0000000..731bc54
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_in_vertical.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:orientation="vertical"
+	android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+	
+	<GridView android:id="@+id/grid"
+	    android:layout_width="wrap_content" 
+	    android:layout_height="wrap_content"
+	    android:numColumns="auto_fit" />
+	    
+    <ImageButton
+        android:src="@drawable/sym_now_playing_pause_1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+   
+	<ImageButton
+        android:src="@drawable/sym_now_playing_pause_1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+        
+	<ImageButton
+        android:src="@drawable/sym_now_playing_pause_1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+         	
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/grid_padding.xml b/tests/FrameworkTest/res/layout/grid_padding.xml
new file mode 100644
index 0000000..bd666e1
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_padding.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/grid"
+	android:layout_width="wrap_content"
+	android:layout_height="wrap_content"
+	android:padding="10dip"
+	android:verticalSpacing="10dp"
+	android:horizontalSpacing="10dp"
+	android:numColumns="auto_fit"
+	android:columnWidth="50dp" />
diff --git a/tests/FrameworkTest/res/layout/grid_scroll_listener.xml b/tests/FrameworkTest/res/layout/grid_scroll_listener.xml
new file mode 100644
index 0000000..c02aed9
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_scroll_listener.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:orientation="vertical"
+	android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+	
+	<GridView android:id="@+id/grid"
+	    android:layout_width="fill_parent" 
+	    android:layout_height="0dip"
+	    android:layout_weight="1"
+	    android:padding="10dip"
+	    android:verticalSpacing="10dp"    
+	    android:horizontalSpacing="10dp"
+	    android:numColumns="auto_fit"
+	    android:columnWidth="60dp"
+	    android:stretchMode="columnWidth"
+	    android:gravity="center"/>
+	    
+    <TextView android:id="@+id/text"
+    	android:layout_width="fill_parent" 
+    	android:layout_height="wrap_content"
+    	android:gravity="center_horizontal"/>
+    	
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/grid_thrasher.xml b/tests/FrameworkTest/res/layout/grid_thrasher.xml
new file mode 100644
index 0000000..1a260df
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_thrasher.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:orientation="vertical"
+	android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+	
+	<GridView android:id="@+id/grid"
+	    android:layout_width="fill_parent" 
+		android:layout_height="fill_parent"
+	    android:padding="10dip"
+	    android:verticalSpacing="10dp"    
+	    android:horizontalSpacing="10dp"
+	    android:numColumns="auto_fit"
+	    android:columnWidth="60dp"
+	    android:stretchMode="columnWidth"
+	    android:gravity="center"/>
+	    
+    <TextView android:id="@+id/text"
+    	android:layout_width="fill_parent" 
+    	android:layout_height="wrap_content"
+    	android:gravity="center_horizontal"/>
+    	
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/include_button.xml b/tests/FrameworkTest/res/layout/include_button.xml
new file mode 100644
index 0000000..5857fa3
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/include_button.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/included_button"
+    android:text="@string/include_button"        
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content" />
diff --git a/tests/FrameworkTest/res/layout/include_button_with_size.xml b/tests/FrameworkTest/res/layout/include_button_with_size.xml
new file mode 100644
index 0000000..0cd8eaa
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/include_button_with_size.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/included_button"
+    android:text="@string/include_button"        
+    android:layout_width="23dip"
+    android:layout_height="23dip" />
diff --git a/tests/FrameworkTest/res/layout/include_tag.xml b/tests/FrameworkTest/res/layout/include_tag.xml
new file mode 100644
index 0000000..d1047f1
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/include_tag.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <TextView
+        android:text="@string/include_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <include
+        layout="@layout/include_button" />
+
+    <include
+        layout="@layout/include_button"
+        android:id="@+id/included_button_overriden"
+        android:layout_width="237dip"
+        android:layout_height="123dip" />
+
+    <include
+        layout="@layout/include_button"
+        android:id="@+id/included_button_visibility"
+        android:visibility="invisible" />
+    
+    <include
+        layout="@layout/include_button_with_size"
+        android:id="@+id/included_button_with_size" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/inflated_expandablelistview.xml b/tests/FrameworkTest/res/layout/inflated_expandablelistview.xml
new file mode 100644
index 0000000..d01e7c5
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/inflated_expandablelistview.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/elv"
+        android:layout_height="fill_parent"
+        android:layout_width="fill_parent" />
diff --git a/tests/FrameworkTest/res/layout/linear_layout_buttons.xml b/tests/FrameworkTest/res/layout/linear_layout_buttons.xml
new file mode 100644
index 0000000..f60692a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_buttons.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <Button
+        android:id="@+id/button1"
+        android:layout_width="fill_parent"
+        android:layout_height="0sp"
+        android:layout_weight="1"
+        android:text="@string/keypad_one"/>
+
+    <Button
+        android:id="@+id/button2"
+        android:layout_width="fill_parent"
+        android:layout_height="0sp"
+        android:layout_weight="1"
+        android:text="@string/keypad_two"/>
+
+    <Button
+        android:id="@+id/button3"
+        android:layout_width="fill_parent"
+        android:layout_height="0sp"
+        android:layout_weight="1"
+        android:text="@string/keypad_three"/>
+
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_edittext_then_button.xml b/tests/FrameworkTest/res/layout/linear_layout_edittext_then_button.xml
new file mode 100644
index 0000000..21e7399
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_edittext_then_button.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <EditText
+        android:id="@+id/editText"
+        android:layout_width="fill_parent"
+        android:layout_height="0sp"
+        android:layout_weight="1"/>
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="fill_parent"
+        android:layout_height="0sp"
+        android:layout_weight="1"
+        android:text="@string/keypad_one"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_grid.xml b/tests/FrameworkTest/res/layout/linear_layout_grid.xml
new file mode 100644
index 0000000..81f7b15
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_grid.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout android:id="@+id/column1"
+        android:layout_width="fill_parent"
+        android:layout_height="0sp"
+        android:layout_weight="1"
+        android:orientation="horizontal">
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_one"/>
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_two"/>
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_three"/>
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/column2"
+        android:layout_width="fill_parent"
+        android:layout_height="0sp"
+        android:layout_weight="1"
+        android:orientation="horizontal">
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_four"/>
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_five"/>
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_six"/>
+    </LinearLayout>
+
+    <LinearLayout android:id="@+id/column3"
+        android:layout_width="fill_parent"
+        android:layout_height="0sp"
+        android:layout_weight="1"
+        android:orientation="horizontal">
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_seven"/>
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_eight"/>
+
+        <Button
+            android:layout_width="0sp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:text="@string/keypad_nine"/>
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_listview_height.xml b/tests/FrameworkTest/res/layout/linear_layout_listview_height.xml
new file mode 100644
index 0000000..10ef2ce
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_listview_height.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    
+    <!-- Outer linear layout providing vertical layout -->
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+        
+        <!-- The control buttons -->
+        <LinearLayout
+            android:orientation="horizontal"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content" >
+            
+            <Button
+                android:id="@+id/button1"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/linear_listheight_fixed"/>
+        
+            <Button
+                android:id="@+id/button2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/linear_listheight_fill"/>
+        
+            <Button
+                android:id="@+id/button3"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/linear_listheight_hide"/>
+        </LinearLayout>
+        
+        <!-- The list view -->
+        <ListView 
+            android:id="@+id/inner_list"
+            android:layout_width="200dip"
+            android:layout_height="fill_parent"
+            android:background="@android:drawable/spinner_dropdown_background"
+            android:divider="@android:drawable/divider_horizontal_bright" />
+ 
+    </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_spinner_then_button.xml b/tests/FrameworkTest/res/layout/linear_layout_spinner_then_button.xml
new file mode 100644
index 0000000..7ed245b
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_spinner_then_button.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+        
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+   android:orientation="horizontal"
+   android:layout_width="fill_parent"
+   android:layout_height="wrap_content">
+
+   <Spinner android:id="@+id/reminder_value"
+       android:layout_width="0dip"
+       android:layout_height="wrap_content"
+       android:layout_weight="0.7"
+       android:entries="@array/reminder_minutes_labels"/>
+
+   <Button android:id="@+id/reminder_remove"
+       android:layout_width="0dip"
+       android:layout_height="wrap_content"
+       android:layout_weight="0.3"
+       android:text="@string/show" />
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_textviews.xml b/tests/FrameworkTest/res/layout/linear_layout_textviews.xml
new file mode 100644
index 0000000..84a898c
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_textviews.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout"
+    android:background="#FFFF0000"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <EditText
+        android:id="@+id/editText1"
+        android:text="@string/text"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1.0" />
+
+    <EditText
+        android:id="@+id/editText2"
+        android:text="@string/text"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1.0" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_weight.xml b/tests/FrameworkTest/res/layout/linear_layout_weight.xml
new file mode 100644
index 0000000..bb138df
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_weight.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout"
+    android:background="#FFFFFFFF"
+    android:orientation="horizontal"
+    android:layout_width="87dip"
+    android:layout_height="wrap_content">
+
+    <View
+        android:id="@+id/child1"
+        android:background="#FFFF0000"
+        android:layout_width="20dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1.0" />
+
+    <View
+        android:id="@+id/child2"
+        android:background="#FF00FF00"
+        android:layout_width="20dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1.0" />
+
+    <View
+        android:background="#FF0000FF"
+        android:id="@+id/child3"
+        android:layout_width="20dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1.0" />
+
+    <View
+        android:background="#FFFF00FF"
+        android:id="@+id/child4"
+        android:layout_width="20dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1.0" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_dividers.xml b/tests/FrameworkTest/res/layout/list_dividers.xml
new file mode 100644
index 0000000..b56511e6
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_dividers.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <Button
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <ListView android:id="@android:id/list"
+        android:paddingRight="15dip"
+        android:layout_marginLeft="50dip"
+        android:layout_width="150dip"
+        android:layout_height="300dip" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_filter.xml b/tests/FrameworkTest/res/layout/list_filter.xml
new file mode 100644
index 0000000..cea518c
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_filter.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+    
+    <FrameLayout android:id="@+id/frame"
+        android:layout_width="fill_parent" 
+        android:layout_height="0dip"
+        android:layout_weight="1">
+
+        <ListView android:id="@android:id/list"
+            android:layout_width="fill_parent" 
+            android:layout_height="fill_parent"
+            android:drawSelectorOnTop="false" />
+            
+    </FrameLayout>
+    
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="fill_parent" 
+        android:layout_height="wrap_content">
+        
+        <Button android:id="@+id/hide"
+            android:layout_width="wrap_content" 
+            android:layout_height="wrap_content"
+            android:text="@string/hide" />
+         
+        <Button android:id="@+id/show"
+            android:layout_width="wrap_content" 
+            android:layout_height="wrap_content"
+            android:text="@string/show" /> 
+            
+    </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_in_horizontal.xml b/tests/FrameworkTest/res/layout/list_in_horizontal.xml
new file mode 100644
index 0000000..371cb84
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_in_horizontal.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <TableRow>
+
+        <ListView android:id="@+id/list" />
+
+        <ImageButton android:src="@drawable/sym_now_playing_pause_1" />
+
+    </TableRow>
+
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/list_in_vertical.xml b/tests/FrameworkTest/res/layout/list_in_vertical.xml
new file mode 100644
index 0000000..0ea2475
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_in_vertical.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+        <ListView android:id="@+id/list"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content" />
+
+        <ImageButton
+            android:src="@drawable/sym_now_playing_pause_1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <ImageButton
+            android:src="@drawable/sym_now_playing_pause_1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+
+        <ImageButton
+            android:src="@drawable/sym_now_playing_pause_1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" />
+         	
+    </LinearLayout>
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/list_recycler_profiling.xml b/tests/FrameworkTest/res/layout/list_recycler_profiling.xml
new file mode 100644
index 0000000..9678eb7
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_recycler_profiling.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <ListView android:id="@+id/list"
+        android:layout_width="fill_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1.0" />
+
+    <ImageButton android:id="@+id/pause"
+        android:src="@drawable/sym_now_playing_pause_1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_scroll_listener.xml b/tests/FrameworkTest/res/layout/list_scroll_listener.xml
new file mode 100644
index 0000000..001296a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_scroll_listener.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:orientation="vertical"
+	android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+	
+	<ListView android:id="@android:id/list"
+	    android:layout_width="fill_parent" 
+	    android:layout_height="0dip"
+	    android:layout_weight="1"
+	    android:drawSelectorOnTop="false"/>
+	    
+    <TextView android:id="@+id/text"
+    	android:layout_width="fill_parent" 
+    	android:layout_height="wrap_content"
+    	android:gravity="center_horizontal"/>
+    	
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_take_focus_from_side.xml b/tests/FrameworkTest/res/layout/list_take_focus_from_side.xml
new file mode 100644
index 0000000..cf141cc
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_take_focus_from_side.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+    
+    <ListView android:id="@android:id/list"
+        android:layout_width="0dip" 
+        android:layout_weight="1"
+        android:layout_height="fill_parent"
+        android:drawSelectorOnTop="false"/>
+        
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="wrap_content" 
+        android:layout_height="fill_parent">
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+         <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+         <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+         <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+         <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+         <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+         <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+         <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+         <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />  
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/side_button_label" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_thrasher.xml b/tests/FrameworkTest/res/layout/list_thrasher.xml
new file mode 100644
index 0000000..001296a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_thrasher.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:orientation="vertical"
+	android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+	
+	<ListView android:id="@android:id/list"
+	    android:layout_width="fill_parent" 
+	    android:layout_height="0dip"
+	    android:layout_weight="1"
+	    android:drawSelectorOnTop="false"/>
+	    
+    <TextView android:id="@+id/text"
+    	android:layout_width="fill_parent" 
+    	android:layout_height="wrap_content"
+    	android:gravity="center_horizontal"/>
+    	
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_with_button_above.xml b/tests/FrameworkTest/res/layout/list_with_button_above.xml
new file mode 100644
index 0000000..25db016
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_with_button_above.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<!-- Simple layout with a button and a list below, can be used to build more
+ sophisticated test cases by adding stuff to the list programatically.-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/layout"
+        android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+
+    <Button android:id="@+id/button"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/button_above_list_label"/>
+
+
+    <ListView android:id="@android:id/list"
+        android:layout_width="fill_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:paddingTop="2dip"
+        android:drawSelectorOnTop="false"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_with_disappearing_item_bug_item.xml b/tests/FrameworkTest/res/layout/list_with_disappearing_item_bug_item.xml
new file mode 100644
index 0000000..0163d96
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_with_disappearing_item_bug_item.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- A layout is needed to reprod the bug. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight">
+
+    <TextView 
+        android:id="@+id/text1"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:gravity="center_vertical"
+        android:paddingLeft="27dip"
+    />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_with_empty_view.xml b/tests/FrameworkTest/res/layout/list_with_empty_view.xml
new file mode 100644
index 0000000..00d81a7
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_with_empty_view.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+ 
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <ListView android:id="@android:id/list"
+        android:drawSelectorOnTop="false"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"/>
+
+    <TextView android:id="@+id/empty"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:gravity="center"
+        android:textSize="36sp"
+        android:textColor="#999"
+        android:visibility="gone"
+        android:text="@string/empty_list" />
+
+</FrameLayout>    
diff --git a/tests/FrameworkTest/res/layout/longpress.xml b/tests/FrameworkTest/res/layout/longpress.xml
new file mode 100644
index 0000000..ef3672c
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/longpress.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <View android:id="@+id/simple_view"
+        android:background="@drawable/blue"
+        android:layout_width="20dip"
+        android:layout_height="20dip"
+        android:focusable="true" />
+    
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/mail_message.xml b/tests/FrameworkTest/res/layout/mail_message.xml
new file mode 100644
index 0000000..ed52751
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/mail_message.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<!-- A layout similar to a gmail message.  useful for setting up tests, like
+ a list with a list of messages.-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <TextView android:id="@+id/subject"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content"/>
+
+    <WebView android:id="@+id/body"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/merge_child.xml b/tests/FrameworkTest/res/layout/merge_child.xml
new file mode 100644
index 0000000..9972924
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/merge_child.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <TextView
+        android:text="@string/include_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <TextView
+        android:text="@string/include_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <TextView
+        android:text="@string/include_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</merge>
diff --git a/tests/FrameworkTest/res/layout/merge_tag.xml b/tests/FrameworkTest/res/layout/merge_tag.xml
new file mode 100644
index 0000000..9eec493
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/merge_tag.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <TextView
+        android:text="@string/include_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <TextView
+        android:text="@string/include_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <TextView
+        android:text="@string/include_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <TextView
+        android:text="@string/include_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <include layout="@layout/merge_child" />
+
+</merge>
diff --git a/tests/FrameworkTest/res/layout/popup_window_visibility.xml b/tests/FrameworkTest/res/layout/popup_window_visibility.xml
new file mode 100644
index 0000000..21c94bb
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/popup_window_visibility.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+    
+    <FrameLayout android:id="@+id/frame"
+        android:layout_width="fill_parent" 
+        android:layout_height="0dip"
+        android:layout_weight="1">
+
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="fill_parent" 
+            android:layout_height="fill_parent">
+                
+            <Spinner android:id="@+id/spinner"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" />
+        
+            <AutoCompleteTextView android:id="@+id/auto"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"/>
+                
+        </LinearLayout>
+        
+    </FrameLayout>
+    
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="fill_parent" 
+        android:layout_height="wrap_content">
+        
+        <Button android:id="@+id/hide"
+            android:layout_width="wrap_content" 
+            android:layout_height="wrap_content"
+            android:text="@string/hide" />
+         
+        <Button android:id="@+id/show"
+            android:layout_width="wrap_content" 
+            android:layout_height="wrap_content"
+            android:text="@string/show" /> 
+            
+    </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/pre_draw_listener.xml b/tests/FrameworkTest/res/layout/pre_draw_listener.xml
new file mode 100644
index 0000000..d348d9f
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/pre_draw_listener.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent" 
+    android:layout_height="fill_parent">
+    
+
+	<ScrollView 
+		android:orientation="vertical"
+        android:layout_width="fill_parent" 
+        android:layout_height="0dip"
+        android:layout_weight="1">
+        
+        <view class="com.android.frameworktest.view.PreDrawListener$MyLinearLayout" android:id="@+id/frame"
+            android:orientation="vertical"
+            android:layout_width="fill_parent" 
+            android:layout_height="fill_parent" />
+
+    </ScrollView>
+        
+    <Button android:id="@+id/go"
+        android:layout_width="wrap_content" 
+        android:layout_height="wrap_content"
+        android:text="@string/go" />
+         
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/remote_view_host.xml b/tests/FrameworkTest/res/layout/remote_view_host.xml
new file mode 100644
index 0000000..dc52181
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/remote_view_host.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/remote_view_test_bad_1.xml b/tests/FrameworkTest/res/layout/remote_view_test_bad_1.xml
new file mode 100644
index 0000000..6a65976
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/remote_view_test_bad_1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linear"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <EditText android:id="@+id/edit"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+           
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/remote_view_test_bad_2.xml b/tests/FrameworkTest/res/layout/remote_view_test_bad_2.xml
new file mode 100644
index 0000000..70613c3
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/remote_view_test_bad_2.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linear"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <WebView android:id="@+id/web"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+            
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/remote_view_test_good.xml b/tests/FrameworkTest/res/layout/remote_view_test_good.xml
new file mode 100644
index 0000000..54f4db9
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/remote_view_test_good.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/linear"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <TextView android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+        
+    <ImageView android:id="@+id/image"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+        
+    <FrameLayout android:id="@+id/frame"
+        android:layout_width="10dip"
+        android:layout_height="10dip" />
+        
+    <RelativeLayout android:id="@+id/relative"
+        android:layout_width="10dip"
+        android:layout_height="10dip" />
+   
+    <AbsoluteLayout android:id="@+id/absolute"
+        android:layout_width="10dip"
+        android:layout_height="10dip" />       
+        
+    <ProgressBar android:id="@+id/progress"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />      
+
+    <ImageButton android:id="@+id/image_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/scroll_to_rect_with_internal_scroll.xml b/tests/FrameworkTest/res/layout/scroll_to_rect_with_internal_scroll.xml
new file mode 100644
index 0000000..d22122d
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/scroll_to_rect_with_internal_scroll.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/scroll_view_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<!-- Demonstrates scrolling with a ScrollView. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scrollView"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:scrollbars="none">
+
+    <LinearLayout
+        android:id="@+id/layout"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+
+        <Button android:id="@+id/scrollToBlob"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/scroll_top_button"/>
+
+        <TextView android:id="@+id/blob"
+            android:layout_width="fill_parent"
+            android:layout_height="80dip"
+            android:layout_marginTop="500dip"
+            android:layout_marginBottom="5dip"/>
+
+
+    </LinearLayout>
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/scroll_to_rectangle.xml b/tests/FrameworkTest/res/layout/scroll_to_rectangle.xml
new file mode 100644
index 0000000..0839b1a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/scroll_to_rectangle.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/scroll_view_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<!-- Demonstrates scrolling with a ScrollView. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scrollView"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:scrollbars="none">
+
+    <LinearLayout
+        android:id="@+id/layout"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+
+        <Button android:id="@+id/scrollToRectFromTop"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/scroll_top_button"/>
+
+        <Button android:id="@+id/scrollToRectFromTop2"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:paddingBottom="10dip"
+            android:text="@string/scroll_top_button2"/>
+
+        <TextView android:id="@+id/topBlob"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dip"
+            android:layout_marginBottom="5dip"/>
+
+        <TextView android:id="@+id/childToMakeVisible"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dip"
+            android:layout_marginBottom="5dip"
+            android:text="@string/scroll_to_me"/>
+
+        <TextView android:id="@+id/bottomBlob"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dip"
+            android:layout_marginBottom="5dip"/>
+
+        <Button android:id="@+id/scrollToRectFromBottom2"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="10dip"
+            android:text="@string/scroll_bottom_button2"/>
+
+        <Button android:id="@+id/scrollToRectFromBottom"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/scroll_bottom_button"/>
+
+
+    </LinearLayout>
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/scrollview_linear_layout.xml b/tests/FrameworkTest/res/layout/scrollview_linear_layout.xml
new file mode 100644
index 0000000..536d2ed
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/scrollview_linear_layout.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scrollView"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:scrollbars="none">
+
+    <LinearLayout
+        android:id="@+id/layout"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+    </LinearLayout>
+
+
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/scrollview_with_webviews.xml b/tests/FrameworkTest/res/layout/scrollview_with_webviews.xml
new file mode 100644
index 0000000..79634752
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/scrollview_with_webviews.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/scrollView"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:scrollbars="none">
+
+    <LinearLayout
+        android:id="@+id/layout"
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content">
+
+
+        <WebView android:id="@+id/wb1"
+             android:layout_width="fill_parent"
+             android:layout_height="wrap_content"/>
+
+        <Button android:id="@+id/button"
+             android:layout_width="fill_parent"
+             android:layout_height="wrap_content"/>
+
+        <WebView android:id="@+id/wb2"
+             android:layout_width="fill_parent"
+             android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/table_layout_cell_span.xml b/tests/FrameworkTest/res/layout/table_layout_cell_span.xml
new file mode 100644
index 0000000..26831e4
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_cell_span.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <TableRow>
+        <TextView android:id="@+id/a"
+            android:text="@string/table_layout_a"
+            android:background="#FFFF0000"
+            android:padding="3dip" />
+        <TextView android:id="@+id/b"
+            android:text="@string/table_layout_b"
+            android:background="#FF00FF00"
+            android:padding="3dip" />
+        <TextView android:id="@+id/c"
+            android:text="@string/table_layout_c"
+            android:background="#FF0000FF"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <TextView  android:id="@+id/spanThenCell"
+            android:text="@string/table_layout_d"
+            android:layout_span="2"
+            android:gravity="center_horizontal"
+            android:background="#FF0000FF"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_e"
+            android:background="#FF00FF00"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <TextView
+            android:text="@string/table_layout_f"
+            android:background="#FFFF00FF"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_g"
+            android:background="#FF00FF00"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_h"
+            android:background="#FFFF0000"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <TextView
+            android:text="@string/table_layout_a"
+            android:background="#FF00FF00"
+            android:padding="3dip" />
+        <TextView android:id="@+id/cellThenSpan"
+            android:text="@string/table_layout_b"
+            android:layout_span="2"
+            android:gravity="center_horizontal"
+            android:background="#FF0000FF"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <TextView android:id="@+id/span"
+            android:text="@string/table_layout_g"
+            android:layout_span="3"
+            android:gravity="center_horizontal"
+            android:background="#FFC0C0C0"
+            android:padding="3dip" />
+    </TableRow>
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/table_layout_fixed_width.xml b/tests/FrameworkTest/res/layout/table_layout_fixed_width.xml
new file mode 100644
index 0000000..91d9128
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_fixed_width.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <TableRow>
+        <View android:id="@+id/fixed_height"
+            android:layout_height="48dip"
+            android:background="#FF909090" />
+        <TextView android:id="@+id/fixed_width"
+            android:layout_width="150dip"
+            android:text="@string/table_layout_export"
+            android:background="#FFFF0000"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_export_shortcut"
+            android:background="#FF00FFFF"
+            android:gravity="right"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <View
+            android:layout_height="48dip"
+            android:background="#FF909090" />
+        <TextView android:id="@+id/non_fixed_width"
+            android:text="@string/table_layout_export"
+            android:background="#FFFF0000"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_export_shortcut"
+            android:background="#FF00FFFF"
+            android:gravity="right"
+            android:padding="3dip" />
+    </TableRow>
+
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/table_layout_horizontal_gravity.xml b/tests/FrameworkTest/res/layout/table_layout_horizontal_gravity.xml
new file mode 100644
index 0000000..dee81a5
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_horizontal_gravity.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:stretchColumns="1">
+
+    <TableRow>
+        <TextView android:id="@+id/reference"
+            android:layout_column="1"
+            android:background="#FF0000FF"
+            android:text="@string/table_layout_open"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_open_shortcut"
+            android:gravity="right"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <!-- Horizontally centers the content of the cell -->
+        <TextView android:id="@+id/center"
+            android:layout_column="1"
+            android:text="@string/table_layout_save_as"
+            android:background="#FFFF0000"
+            android:layout_gravity="center_horizontal"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_save_as_shortcut"
+            android:background="#FFFF00FF"
+            android:gravity="right"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <View
+            android:layout_height="24dip"
+            android:background="#FF909090" />
+        <!-- Aligns the content of the cell to the bottom right -->
+        <TextView android:id="@+id/bottomRight"
+            android:text="@string/table_layout_export"
+            android:background="#FFFF0000"
+            android:layout_gravity="right|bottom"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_export_shortcut"
+            android:background="#FF00FFFF"
+            android:gravity="right"
+            android:padding="3dip" />
+    </TableRow>
+
+
+    <TableRow>
+        <TextView android:id="@+id/left"
+            android:layout_column="1"
+            android:background="#FF0000FF"
+            android:text="@string/table_layout_open"
+            android:padding="3dip" />
+        <TextView
+            android:text="@string/table_layout_open_shortcut"
+            android:gravity="right"
+            android:padding="3dip" />
+    </TableRow>
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/table_layout_vertical_gravity.xml b/tests/FrameworkTest/res/layout/table_layout_vertical_gravity.xml
new file mode 100644
index 0000000..6a8b784
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_vertical_gravity.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <TableRow>
+        <View android:id="@+id/reference1"
+            android:layout_height="96dip"
+            android:background="#FF909090" />
+        <TextView
+            android:background="#FF0000FF"
+            android:text="@string/table_layout_open"
+            android:padding="3dip" />
+        <TextView android:id="@+id/cell_top"
+            android:background="#FF00FF00"
+            android:layout_gravity="top"
+            android:text="@string/table_layout_open_shortcut"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <View android:id="@+id/reference2"
+            android:layout_height="96dip"
+            android:background="#FF909090" />
+        <TextView
+            android:background="#FF0000FF"
+            android:text="@string/table_layout_open"
+            android:padding="3dip" />
+        <TextView android:id="@+id/cell_center"
+            android:background="#FF00FF00"
+            android:layout_gravity="center_vertical"
+            android:text="@string/table_layout_open_shortcut"
+            android:padding="3dip" />
+    </TableRow>
+
+    <TableRow>
+        <View android:id="@+id/reference3"
+            android:layout_height="96dip"
+            android:background="#FF909090" />
+        <TextView
+            android:background="#FF0000FF"
+            android:text="@string/table_layout_open"
+            android:padding="3dip" />
+        <TextView android:id="@+id/cell_bottom"
+            android:background="#FF00FF00"
+            android:layout_gravity="bottom"
+            android:text="@string/table_layout_open_shortcut"
+            android:padding="3dip" />
+    </TableRow>
+
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/table_layout_weight.xml b/tests/FrameworkTest/res/layout/table_layout_weight.xml
new file mode 100644
index 0000000..432c04a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_weight.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+
+    <TableRow android:id="@+id/row"
+        android:weightSum="0.9">
+        <View android:id="@+id/cell1"
+            android:layout_width="0dip"
+            android:layout_weight="0.3"
+            android:layout_height="190dip"
+            android:background="#FF0000FF" />
+        <View android:id="@+id/cell2"
+            android:layout_width="0dip"
+            android:layout_weight="0.3"
+            android:layout_height="190dip"
+            android:background="#FFFFFFFF" />
+        <View android:id="@+id/cell3"
+            android:layout_width="0dip"
+            android:layout_weight="0.3"
+            android:layout_height="190dip"
+            android:background="#FFFF0000" />
+    </TableRow>
+
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/translucent_background.xml b/tests/FrameworkTest/res/layout/translucent_background.xml
new file mode 100644
index 0000000..6b6e1cf
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/translucent_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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.
+-->
+
+<!-- Demonstrates an activity with a fancy translucent background.
+     See corresponding Java code com.android.sdk.app.TranslucentBackground.java. -->
+
+<!-- This screen consists of a single text field that displays some text. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+    android:layout_width="fill_parent" android:layout_height="fill_parent"
+    android:gravity="center_vertical|center_horizontal"
+    android:text="@string/translucent_background"/>
diff --git a/tests/FrameworkTest/res/layout/viewgroupchildren.xml b/tests/FrameworkTest/res/layout/viewgroupchildren.xml
new file mode 100644
index 0000000..a5bb7cb
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/viewgroupchildren.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<!-- Demonstrates adding/removing views from ViewGroup. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/group"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/viewstub.xml b/tests/FrameworkTest/res/layout/viewstub.xml
new file mode 100644
index 0000000..9a6f376
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/viewstub.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <Button android:id="@+id/vis"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/visibility_1_vis" />
+
+    <ViewStub android:id="@+id/viewStub"
+        android:layout="@layout/linear_layout_buttons"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <ViewStub android:id="@+id/viewStubWithId"
+        android:inflatedId="@+id/stub_inflated"
+        android:layout="@layout/linear_layout_buttons"
+        android:layout_width="47dip"
+        android:layout_height="127dip" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/visibility.xml b/tests/FrameworkTest/res/layout/visibility.xml
new file mode 100644
index 0000000..b4f9d8b
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/visibility.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<!-- Demonstrates changing view visibility. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <LinearLayout
+      android:orientation="vertical"
+      android:background="@drawable/box"
+      android:layout_width="fill_parent"
+      android:layout_height="wrap_content">
+
+      <TextView android:id="@+id/refUp"
+          android:background="@drawable/red"
+          android:layout_width="fill_parent"
+          android:layout_height="wrap_content"
+          android:text="@string/visibility_1_view_1"/>
+
+      <TextView android:id="@+id/victim"
+          android:background="@drawable/green"
+          android:layout_width="fill_parent"
+          android:layout_height="wrap_content"
+          android:text="@string/visibility_1_view_2"/>
+
+      <TextView android:id="@+id/refDown"
+          android:background="@drawable/blue"
+          android:layout_width="fill_parent"
+          android:layout_height="wrap_content"
+          android:text="@string/visibility_1_view_3"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <Button android:id="@+id/vis"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/visibility_1_vis"/>
+
+        <Button android:id="@+id/invis"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/visibility_1_invis"/>
+
+        <Button android:id="@+id/gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/visibility_1_gone"/>
+
+    </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/weight_sum.xml b/tests/FrameworkTest/res/layout/weight_sum.xml
new file mode 100644
index 0000000..249dc68
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/weight_sum.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<LinearLayout android:id="@+id/container" xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:weightSum="1.0"
+    android:gravity="center_horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <Button android:id="@+id/child"
+        android:layout_width="0dip"
+        android:layout_weight="0.5"
+        android:layout_height="wrap_content"
+        android:text="@string/visibility_1_vis"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/with_bitmap_background.xml b/tests/FrameworkTest/res/layout/with_bitmap_background.xml
new file mode 100644
index 0000000..b32d99e
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/with_bitmap_background.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<LinearLayout android:id="@+id/container" xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:background="@drawable/bitmap_drawable">
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/zero_sized.xml b/tests/FrameworkTest/res/layout/zero_sized.xml
new file mode 100644
index 0000000..c837bf9
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/zero_sized.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, 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.
+*/
+-->
+
+<!-- Demonstrates changing view visibility. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+
+    <View android:id="@+id/dimension"
+        android:background="#ffff0000"
+        android:layout_width="42dip"
+        android:layout_height="42dip" />
+
+    <View android:id="@+id/noWidth"
+          android:background="#ff00ff00"
+        android:layout_width="0dip"
+        android:layout_height="42dip" />
+
+    <View android:id="@+id/noHeight"
+          android:background="#ff0000ff"
+        android:layout_width="42dip"
+        android:layout_height="0dip" />
+
+    <View android:id="@+id/noDimension"
+        android:background="#ffffffff"
+        android:layout_width="0dip"
+        android:layout_height="0dip" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/values/arrays.xml b/tests/FrameworkTest/res/values/arrays.xml
new file mode 100644
index 0000000..f76da85
--- /dev/null
+++ b/tests/FrameworkTest/res/values/arrays.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string-array name="reminder_minutes_labels">
+        <item>5 minutes</item>
+        <item>10 minutes</item>
+        <item>15 minutes</item>
+        <item>20 minutes</item>
+        <item>25 minutes</item>
+        <item>30 minutes</item>
+        <item>45 minutes</item>
+        <item>1 hour</item>
+        <item>2 hours</item>
+        <item>3 hours</item>
+        <item>12 hours</item>
+        <item>24 hours</item>
+        <item>2 days</item>
+        <item>1 week</item>
+    </string-array>
+</resources>
diff --git a/tests/FrameworkTest/res/values/attrs.xml b/tests/FrameworkTest/res/values/attrs.xml
new file mode 100644
index 0000000..bf59e74
--- /dev/null
+++ b/tests/FrameworkTest/res/values/attrs.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+     <declare-styleable name="SelectableRowView">
+        <attr name="numRows" format="integer" />
+    </declare-styleable>
+</resources>
diff --git a/tests/FrameworkTest/res/values/colors.xml b/tests/FrameworkTest/res/values/colors.xml
new file mode 100644
index 0000000..f881660
--- /dev/null
+++ b/tests/FrameworkTest/res/values/colors.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/values/colors.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<resources>
+    <drawable name="red">#ffff0000</drawable>
+    <drawable name="blue">#ff0000ff</drawable>
+    <drawable name="green">#ff00ff00</drawable>
+    <drawable name="yellow">#ffffff00</drawable>
+</resources>
diff --git a/tests/FrameworkTest/res/values/strings.xml b/tests/FrameworkTest/res/values/strings.xml
new file mode 100644
index 0000000..05b57e0
--- /dev/null
+++ b/tests/FrameworkTest/res/values/strings.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">FrameworkTestApplication</string>
+
+    <!-- FocusAfterRemoval -->
+    <string name="left_top">parent GONE</string>
+    <string name="left_bottom">parent INVISIBLE</string>
+    <string name="right_top">me GONE</string>
+    <string name="right_bottom">me INVISIBLE</string>
+
+    <!-- Strings for the 12 key dialer -->
+    <string name="keypad_one">1</string>
+    <string name="keypad_two">"2\nabc"</string>
+    <string name="keypad_three">"3\ndef"</string>
+    <string name="keypad_four">"4\nghi"</string>
+    <string name="keypad_five">"5\njkl"</string>
+    <string name="keypad_six">"6\nmno"</string>
+    <string name="keypad_seven">"7\npqrs"</string>
+    <string name="keypad_eight">"8\ntuv"</string>
+    <string name="keypad_nine">"9\nwxyz"</string>
+    <string name="keypad_zero">0</string>
+    <string name="keypad_star">*</string>
+    <string name="keypad_pound">"#"</string>
+    
+
+    <!-- HorizontalGravity -->
+    <string name="table_layout_open">Open\u2026</string>
+    <string name="table_layout_open_shortcut">Ctrl-O</string>
+    <string name="table_layout_save_as">Save As\u2026</string>
+    <string name="table_layout_save_as_shortcut">Ctrl-Shift-S</string>
+    <string name="table_layout_export">Export\u2026</string>
+    <string name="table_layout_export_shortcut">Ctrl-E</string>
+
+    <!-- CellSpan -->
+    <string name="table_layout_a">A</string>
+    <string name="table_layout_b">BB</string>
+    <string name="table_layout_c">CCCC</string>
+    <string name="table_layout_d">D</string>
+    <string name="table_layout_e">E</string>
+    <string name="table_layout_f">F</string>
+    <string name="table_layout_g">G</string>
+    <string name="table_layout_h">H</string>
+    
+    <!-- scroll_to_rectangle -->
+    <string name="scroll_top_button">Click to make "hi!" on screen</string>
+    <string name="scroll_top_button2">Click to make blob on screen</string>
+    <string name="scroll_to_me">hi!</string>
+    <string name="scroll_bottom_button2">Click to make blob on screen</string>
+    <string name="scroll_bottom_button">Click to make "hi!" on screen</string>
+
+    <!-- Visibility -->
+    <string name="visibility_1_view_1">View A</string>
+    <string name="visibility_1_view_2">View B</string>
+    <string name="visibility_1_view_3">View C</string>
+    <string name="visibility_1_vis">Visible</string>
+    <string name="visibility_1_invis">Invisible</string>
+    <string name="visibility_1_gone">Gone</string>
+
+    <string name="submit">submit</string>
+    <string name="cancel">cancel</string>
+    <string name="enter_title">enter title</string>
+    <string name="enter_url">enter url</string>
+
+    <!-- List with button above -->
+    <string name="button_above_list_label">Button above list</string>
+    
+    <!-- List take focus from side -->
+    <string name="side_button_label">X</string>
+    
+    <!-- Linear Layout show/hide & sizing -->
+    <string name="linear_listheight_fixed">Fixed Size</string>
+    <string name="linear_listheight_fill">Fill Screen</string>
+    <string name="linear_listheight_hide">Hide</string>
+
+    <!-- Baseline -->
+    <string name="show">Show</string>
+    <string name="time">00:00:00</string>
+    
+    <!-- Drawable -->
+    <string name="minimal_text">a</string>
+    <string name="change_backgrounds">Change backgrounds</string>
+
+    <!-- List with empty view -->
+    <string name="empty_list">Empty list</string>
+    <string name="menu_add">Add</string>
+    <string name="menu_remove">Remove</string>
+
+    <!-- Misc. -->
+    <string name="add_row_button">Add Row</string>
+    <string name="disabled_button">Disabled</string>
+    <string name="translucent_background">Example of how you can make an
+            activity have a translucent background, compositing over
+            whatever is behind it.</string>
+    <string name="text">Lorem ipsum datum carat casus belli honorare</string>
+    
+	<string name="hide">Hide</string>
+    <string name="go">Go</string>
+
+    <string name="include_label">Included views below:</string>
+    <string name="include_button">I was included!</string>
+
+    <string name="view">View</string>
+</resources>
diff --git a/tests/FrameworkTest/res/values/styles.xml b/tests/FrameworkTest/res/values/styles.xml
new file mode 100644
index 0000000..7a90197
--- /dev/null
+++ b/tests/FrameworkTest/res/values/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+    <style name="Theme" parent="android:Theme">
+        <item name="android:windowAnimationStyle">@style/Animation</item>
+    </style>
+
+    <style name="Animation">
+        <item name="android:activityOpenEnterAnimation">@null</item>
+        <item name="android:activityOpenExitAnimation">@null</item>
+        <item name="android:activityCloseEnterAnimation">@null</item>
+        <item name="android:activityCloseExitAnimation">@null</item>
+        <item name="android:taskOpenEnterAnimation">@null</item>
+        <item name="android:taskOpenExitAnimation">@null</item>
+        <item name="android:taskCloseEnterAnimation">@null</item>
+        <item name="android:taskCloseExitAnimation">@null</item>
+        <item name="android:taskToFrontEnterAnimation">@null</item>
+        <item name="android:taskToFrontExitAnimation">@null</item>
+        <item name="android:taskToBackEnterAnimation">@null</item>
+        <item name="android:taskToBackExitAnimation">@null</item>
+    </style>
+</resources>
diff --git a/tests/FrameworkTest/src/android/widget/AutoCompleteTextViewSimple.java b/tests/FrameworkTest/src/android/widget/AutoCompleteTextViewSimple.java
new file mode 100644
index 0000000..af16cf8
--- /dev/null
+++ b/tests/FrameworkTest/src/android/widget/AutoCompleteTextViewSimple.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 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.widget;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+public class AutoCompleteTextViewSimple extends Activity 
+        implements OnItemClickListener, OnItemSelectedListener {
+
+    private final String LOG_TAG = "AutoCompleteTextViewSimple";
+    
+    private AutoCompleteTextView mTextView;
+    
+    /** These are cleared by resetItemListeners(), and set by the callback listeners */
+    public boolean mItemClickCalled;
+    public int mItemClickPosition;
+    public boolean mItemSelectedCalled;
+    public int mItemSelectedPosition;
+    public boolean mNothingSelectedCalled;
+
+    @Override
+    protected void onCreate(Bundle icicle)
+    {
+        // Be sure to call the super class.
+        super.onCreate(icicle);
+
+        // setup layout & views
+        setContentView(R.layout.autocompletetextview_simple);
+        mTextView = (AutoCompleteTextView) findViewById(R.id.autocompletetextview1);
+        
+        // configure callbacks used for monitoring
+        mTextView.setOnItemClickListener(this);
+        mTextView.setOnItemSelectedListener(this);
+        resetItemListeners();
+        
+        setStringAdapter(5, "a");
+    }
+
+    /**
+     * @return The AutoCompleteTextView used in this test activity.
+     */
+    public AutoCompleteTextView getTextView() {
+        return mTextView;
+    }
+
+    /**
+     * Set the autocomplete data to an adapter containing 0..n strings with a consistent prefix.
+     */
+    public void setStringAdapter(int numSuggestions, String prefix) {
+        // generate the string array
+        String[] strings = new String[numSuggestions];
+        for (int i = 0; i < numSuggestions; ++i) {
+            strings[i] = prefix + String.valueOf(i);
+        }
+        
+        // install it with an adapter
+        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_dropdown_item_1line, strings);
+        mTextView.setAdapter(adapter);
+    }
+    
+    /**
+     * For monitoring OnItemClickListener & OnItemSelectedListener
+     * 
+     * An alternative here would be to provide a set of pass-through callbacks
+     */
+    public void resetItemListeners() {
+        mItemClickCalled = false;
+        mItemClickPosition = -1;
+        mItemSelectedCalled = false;
+        mItemSelectedPosition = -1;
+        mNothingSelectedCalled = false;
+    }
+    
+    /**
+     * Implements OnItemClickListener
+     */
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        Log.d(LOG_TAG, "onItemClick() position " + position);
+        mItemClickCalled = true;
+        mItemClickPosition = position;
+    }
+
+    /** 
+     * Implements OnItemSelectedListener
+     */
+    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+        Log.d(LOG_TAG, "onItemSelected() position " + position);
+        mItemSelectedCalled = true;
+        mItemSelectedPosition = position;
+    }
+
+    /** 
+     * Implements OnItemSelectedListener
+     */
+    public void onNothingSelected(AdapterView<?> parent) {
+        Log.d(LOG_TAG, "onNothingSelected()");
+        mNothingSelectedCalled = true;
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/FrameworkTestApplication.java b/tests/FrameworkTest/src/com/android/frameworktest/FrameworkTestApplication.java
new file mode 100644
index 0000000..e76f387
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/FrameworkTestApplication.java
@@ -0,0 +1,19 @@
+package com.android.frameworktest;
+
+import android.app.LauncherActivity;
+import android.content.Intent;
+
+/**
+ * Holds little snippets of functionality used as code under test for
+ * instrumentation tests of framework code.
+ */
+public class FrameworkTestApplication extends LauncherActivity {
+
+    protected Intent getTargetIntent() {
+        // TODO: partition into categories by label like the sample code app
+        Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
+        targetIntent.addCategory(Intent.CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST);
+        targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return targetIntent;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/activity/TranslucentFancyActivity.java b/tests/FrameworkTest/src/com/android/frameworktest/activity/TranslucentFancyActivity.java
new file mode 100644
index 0000000..9492f91
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/activity/TranslucentFancyActivity.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.activity;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+
+/**
+ * <h3>Fancy Translucent Activity</h3>
+ * 
+ * <p>This demonstrates the how to write an activity that is translucent,
+ * allowing windows underneath to show through, with a fancy
+ * compositing effect.</p>
+ * 
+ * <h4>Demo</h4>
+ * App/Activity/Translucent Fancy
+ * 
+ * <h4>Source files</h4>
+ * <table class="LinkTable">
+ *         <tr>
+ *             <td >src/com/android/samples/app/TranslucentFancyActivity.java</td>
+ *             <td >The Translucent Fancy Screen implementation</td>
+ *         </tr>
+ *         <tr>
+ *             <td >/res/any/layout/translucent_background.xml</td>
+ *             <td >Defines contents of the screen</td>
+ *         </tr>
+ * </table> 
+ */
+public class TranslucentFancyActivity extends Activity
+{
+    /**
+     * Initialization of the Activity after it is first created.  Must at least
+     * call {@link android.app.Activity#setContentView setContentView()} to
+     * describe what is to be displayed in the screen.
+     */
+    @Override
+	protected void onCreate(Bundle icicle)
+    {
+        // Be sure to call the super class.
+        super.onCreate(icicle);
+
+        // Have the system blur any windows behind this one.
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+                WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+        
+        // See assets/res/any/layout/translucent_background.xml for this
+        // view layout definition, which is being set here as
+        // the content of our screen.
+        setContentView(R.layout.translucent_background);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/drawable/BitmapDrawable.java b/tests/FrameworkTest/src/com/android/frameworktest/drawable/BitmapDrawable.java
new file mode 100644
index 0000000..e88ebf9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/drawable/BitmapDrawable.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.drawable;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AbsoluteLayout;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+public class BitmapDrawable extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.with_bitmap_background);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/drawable/DrawableBgMinSize.java b/tests/FrameworkTest/src/com/android/frameworktest/drawable/DrawableBgMinSize.java
new file mode 100644
index 0000000..a382995
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/drawable/DrawableBgMinSize.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.drawable;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AbsoluteLayout;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * Views should obey their background {@link Drawable}'s minimum size
+ * requirements ({@link Drawable#getMinimumHeight()} and
+ * {@link Drawable#getMinimumWidth()}) when possible.
+ * <p>
+ * This Activity exercises a few Views with background {@link Drawable}s. 
+ */
+public class DrawableBgMinSize extends Activity implements OnClickListener {
+    private boolean mUsingBigBg = false;
+    private Drawable mBackgroundDrawable;
+    private Drawable mBigBackgroundDrawable;
+    private Button mChangeBackgroundsButton;
+    
+    private TextView mTextView;
+    private LinearLayout mLinearLayout;
+    private RelativeLayout mRelativeLayout;
+    private FrameLayout mFrameLayout;
+    private AbsoluteLayout mAbsoluteLayout;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        setContentView(R.layout.drawable_background_minimum_size);
+        
+        mBackgroundDrawable = getResources().getDrawable(R.drawable.drawable_background);
+        mBigBackgroundDrawable = getResources().getDrawable(R.drawable.big_drawable_background);
+ 
+        mChangeBackgroundsButton = (Button) findViewById(R.id.change_backgrounds);
+        mChangeBackgroundsButton.setOnClickListener(this);
+        
+        mTextView = (TextView) findViewById(R.id.text_view);
+        mLinearLayout = (LinearLayout) findViewById(R.id.linear_layout);
+        mRelativeLayout = (RelativeLayout) findViewById(R.id.relative_layout);
+        mFrameLayout = (FrameLayout) findViewById(R.id.frame_layout);
+        mAbsoluteLayout = (AbsoluteLayout) findViewById(R.id.absolute_layout);
+
+        changeBackgrounds(mBackgroundDrawable);
+    }
+
+    private void changeBackgrounds(Drawable newBg) {
+        mTextView.setBackgroundDrawable(newBg);
+        mLinearLayout.setBackgroundDrawable(newBg);
+        mRelativeLayout.setBackgroundDrawable(newBg);
+        mFrameLayout.setBackgroundDrawable(newBg);
+        mAbsoluteLayout.setBackgroundDrawable(newBg);
+    }
+    
+    public void onClick(View v) {
+        if (mUsingBigBg) {
+            changeBackgrounds(mBackgroundDrawable);
+        } else {
+            changeBackgrounds(mBigBackgroundDrawable);
+        }
+        
+        mUsingBigBg = !mUsingBigBg;
+    }
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java b/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java
new file mode 100644
index 0000000..2fcaea3
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 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.frameworktest.drawable;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import com.android.frameworktest.R;
+
+public class MutateDrawable extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout layout = new LinearLayout(this);
+
+        Button ok = new Button(this);
+        ok.setId(R.id.a);
+        ok.setBackgroundDrawable(getResources().getDrawable(
+                R.drawable.sym_now_playing_skip_forward_1));
+
+        Button cancel = new Button(this);
+        cancel.setId(R.id.b);
+        cancel.setBackgroundDrawable(getResources().getDrawable(
+                R.drawable.sym_now_playing_skip_forward_1));
+
+        layout.addView(ok);
+        layout.addView(cancel);
+
+        ok.getBackground().mutate().setAlpha(127);
+
+        setContentView(layout);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListSimple.java b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListSimple.java
new file mode 100644
index 0000000..cee1d4d
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListSimple.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.expandablelistview;
+
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.widget.BaseExpandableListAdapter;
+
+import com.android.frameworktest.util.ExpandableListScenario;
+
+public class ExpandableListSimple extends ExpandableListScenario {
+    private static final int[] NUM_CHILDREN = {4, 3, 2, 1, 0};
+
+    @Override
+    protected void init(ExpandableParams params) {
+        params.setNumChildren(NUM_CHILDREN)
+                .setItemScreenSizeFactor(0.14);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+
+        menu.add("Add item").setOnMenuItemClickListener(new OnMenuItemClickListener() {
+            public boolean onMenuItemClick(MenuItem item) {
+                mGroups.add(0, new MyGroup(2));
+                ((BaseExpandableListAdapter) mAdapter).notifyDataSetChanged();
+                return true;
+            }
+        });
+        
+        return true;
+    }
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeaders.java b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeaders.java
new file mode 100644
index 0000000..0155f09
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeaders.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.expandablelistview;
+
+import com.android.frameworktest.util.ExpandableListScenario;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.ExpandableListView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+public class ExpandableListWithHeaders extends ExpandableListScenario {
+    private static final int[] sNumChildren = {1, 4, 3, 2, 6};
+    private static final int sNumOfHeadersAndFooters = 12;
+    
+    @Override
+    protected void init(ExpandableParams params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setNumChildren(sNumChildren)
+                .setItemScreenSizeFactor(0.14)
+                .setConnectAdapter(false);
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final ExpandableListView expandableListView = getExpandableListView();
+        expandableListView.setItemsCanFocus(true);
+
+        for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
+            Button header = new Button(this);
+            header.setText("Header View");
+            expandableListView.addHeaderView(header);
+        }
+
+        for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
+            Button footer = new Button(this);
+            footer.setText("Footer View");
+            expandableListView.addFooterView(footer);
+        }
+        
+        // Set adapter here AFTER we set header and footer views
+        setAdapter(expandableListView);
+    }
+    
+    /**
+     * @return The number of headers (and the same number of footers)
+     */
+    public int getNumOfHeadersAndFooters() {
+        return sNumOfHeadersAndFooters;
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/InflatedExpandableListView.java b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/InflatedExpandableListView.java
new file mode 100644
index 0000000..f1089a1
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/InflatedExpandableListView.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.expandablelistview;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.TextView;
+
+public class InflatedExpandableListView extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        setContentView(R.layout.inflated_expandablelistview);
+        
+        ExpandableListView elv = (ExpandableListView) findViewById(R.id.elv);
+        elv.setAdapter(new MyExpandableListAdapter());
+    }
+
+    public class MyExpandableListAdapter extends BaseExpandableListAdapter {
+        // Sample data set.  children[i] contains the children (String[]) for groups[i].
+        private String[] groups = { "People Names", "Dog Names", "Cat Names", "Fish Names" };
+        private String[][] children = {
+                { "Arnold", "Barry", "Chuck", "David" },
+                { "Ace", "Bandit", "Cha-Cha", "Deuce" },
+                { "Fluffy", "Snuggles" },
+                { "Goldy", "Bubbles" }
+        };
+        
+        public Object getChild(int groupPosition, int childPosition) {
+            return children[groupPosition][childPosition];
+        }
+
+        public long getChildId(int groupPosition, int childPosition) {
+            return childPosition;
+        }
+
+        public int getChildrenCount(int groupPosition) {
+            return children[groupPosition].length;
+        }
+
+        public TextView getGenericView() {
+            // Layout parameters for the ExpandableListView
+            AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT, 64);
+
+            TextView textView = new TextView(InflatedExpandableListView.this);
+            textView.setLayoutParams(lp);
+            // Center the text vertically
+            textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
+            // Set the text starting position
+            textView.setPadding(36, 0, 0, 0);
+            return textView;
+        }
+        
+        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+                View convertView, ViewGroup parent) {
+            TextView textView = getGenericView();
+            textView.setText(getChild(groupPosition, childPosition).toString());
+            return textView;
+        }
+
+        public Object getGroup(int groupPosition) {
+            return groups[groupPosition];
+        }
+
+        public int getGroupCount() {
+            return groups.length;
+        }
+
+        public long getGroupId(int groupPosition) {
+            return groupPosition;
+        }
+
+        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+                ViewGroup parent) {
+            TextView textView = getGenericView();
+            textView.setText(getGroup(groupPosition).toString());
+            return textView;
+        }
+
+        public boolean isChildSelectable(int groupPosition, int childPosition) {
+            return true;
+        }
+
+        public boolean hasStableIds() {
+            return true;
+        }
+
+    }
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/AdjacentVerticalRectLists.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/AdjacentVerticalRectLists.java
new file mode 100644
index 0000000..c4e2705
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/AdjacentVerticalRectLists.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.view.ViewGroup;
+
+/**
+ * {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
+ * and
+ * {@link android.view.View#requestFocus(int, android.graphics.Rect)}
+ * work together to give a newly focused item a hint about the most interesting
+ * rectangle of the previously focused view.  The view taking focus can use this
+ * to set an internal selection more appropriate using this rect.
+ *
+ * This Activity excercises that behavior using three adjacent {@link com.android.frameworktest.util.InternalSelectionView}
+ * that report interesting rects when giving up focus, and use interesting rects
+ * when taking focus to best select the internal row to show as selected.
+ */
+public class AdjacentVerticalRectLists extends Activity {
+
+    private LinearLayout mLayout;
+    private InternalSelectionView mLeftColumn;
+    private InternalSelectionView mMiddleColumn;
+    private InternalSelectionView mRightColumn;
+
+
+    public LinearLayout getLayout() {
+        return mLayout;
+    }
+
+    public InternalSelectionView getLeftColumn() {
+        return mLeftColumn;
+    }
+
+    public InternalSelectionView getMiddleColumn() {
+        return mMiddleColumn;
+    }
+
+    public InternalSelectionView getRightColumn() {
+        return mRightColumn;
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.HORIZONTAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,
+                ViewGroup.LayoutParams.FILL_PARENT, 1);
+
+        mLeftColumn = new InternalSelectionView(this, 5, "left column");
+        mLeftColumn.setLayoutParams(params);
+        mLeftColumn.setPadding(10, 10, 10, 10);
+        mLayout.addView(mLeftColumn);
+
+        mMiddleColumn = new InternalSelectionView(this, 5, "middle column");
+        mMiddleColumn.setLayoutParams(params);
+        mMiddleColumn.setPadding(10, 10, 10, 10);
+        mLayout.addView(mMiddleColumn);
+
+        mRightColumn = new InternalSelectionView(this, 5, "right column");
+        mRightColumn.setLayoutParams(params);
+        mRightColumn.setPadding(10, 10, 10, 10);
+        mLayout.addView(mRightColumn);
+
+        setContentView(mLayout);
+    }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/DescendantFocusability.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/DescendantFocusability.java
new file mode 100644
index 0000000..f0c1980
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/DescendantFocusability.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.focus;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class DescendantFocusability extends Activity {
+
+    public ViewGroup beforeDescendants;
+    public Button beforeDescendantsChild;
+
+    public ViewGroup afterDescendants;
+    public Button afterDescendantsChild;
+
+    public ViewGroup blocksDescendants;
+    public Button blocksDescendantsChild;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.descendant_focusability);
+
+        beforeDescendants = (ViewGroup) findViewById(R.id.beforeDescendants);
+        beforeDescendantsChild = (Button) beforeDescendants.getChildAt(0);
+
+        afterDescendants = (ViewGroup) findViewById(R.id.afterDescendants);
+        afterDescendantsChild = (Button) afterDescendants.getChildAt(0);
+
+        blocksDescendants = (ViewGroup) findViewById(R.id.blocksDescendants);
+        blocksDescendantsChild = (Button) blocksDescendants.getChildAt(0);
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/FocusAfterRemoval.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/FocusAfterRemoval.java
new file mode 100644
index 0000000..6c5f1c4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/FocusAfterRemoval.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.view.View;
+
+/**
+ * Exercises cases where elements of the UI are removed (and
+ * focus should go somewhere).
+ */
+public class FocusAfterRemoval extends Activity {
+
+
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.focus_after_removal);
+
+        final LinearLayout left = (LinearLayout) findViewById(R.id.leftLayout);
+
+        // top left makes parent layout GONE
+        Button topLeftButton = (Button) findViewById(R.id.topLeftButton);
+        topLeftButton.setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                left.setVisibility(View.GONE);
+            }
+        });
+
+        // bottom left makes parent layout INVISIBLE
+        // top left makes parent layout GONE
+        Button bottomLeftButton = (Button) findViewById(R.id.bottomLeftButton);
+        bottomLeftButton.setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                left.setVisibility(View.INVISIBLE);
+            }
+        });
+
+        // top right button makes top right button GONE
+        final Button topRightButton = (Button) findViewById(R.id.topRightButton);
+        topRightButton.setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                topRightButton.setVisibility(View.GONE);
+            }
+        });
+
+        // bottom right button makes bottom right button INVISIBLE
+        final Button bottomRightButton = (Button) findViewById(R.id.bottomRightButton);
+        bottomRightButton.setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                bottomRightButton.setVisibility(View.INVISIBLE);
+            }
+        });
+
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/GoneParentFocusedChild.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/GoneParentFocusedChild.java
new file mode 100644
index 0000000..91bd7b4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/GoneParentFocusedChild.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+/**
+ * An activity that helps test the scenario where a parent is
+ * GONE and one of its children has focus; the activity should get
+ * the key event.  see bug 945150. 
+ */
+public class GoneParentFocusedChild extends Activity {
+    private LinearLayout mGoneGroup;
+    private Button mButton;
+
+    private boolean mUnhandledKeyEvent = false;
+    private LinearLayout mLayout;
+
+    public boolean isUnhandledKeyEvent() {
+        return mUnhandledKeyEvent;
+    }
+
+    public LinearLayout getLayout() {
+        return mLayout;
+    }
+
+    public LinearLayout getGoneGroup() {
+        return mGoneGroup;
+    }
+
+    public Button getButton() {
+        return mButton;
+    }
+
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.HORIZONTAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+
+        mGoneGroup = new LinearLayout(this);
+        mGoneGroup.setOrientation(LinearLayout.HORIZONTAL);
+        mGoneGroup.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+        mButton = new Button(this);
+        mButton.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+
+
+        mGoneGroup.addView(mButton);
+        setContentView(mLayout);
+
+        mGoneGroup.setVisibility(View.GONE);
+        mButton.requestFocus();
+    }
+
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        mUnhandledKeyEvent = true;
+        return true;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/HorizontalFocusSearch.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/HorizontalFocusSearch.java
new file mode 100644
index 0000000..01a9821
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/HorizontalFocusSearch.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.app.Activity;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.TextView;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.content.Context;
+
+public class HorizontalFocusSearch extends Activity {
+
+    private LinearLayout mLayout;
+
+    private Button mLeftTall;
+    private Button mMidShort1Top;
+    private Button mMidShort2Bottom;
+    private Button mRightTall;
+
+
+    public LinearLayout getLayout() {
+        return mLayout;
+    }
+
+    public Button getLeftTall() {
+        return mLeftTall;
+    }
+
+    public Button getMidShort1Top() {
+        return mMidShort1Top;
+    }
+
+    public Button getMidShort2Bottom() {
+        return mMidShort2Bottom;
+    }
+
+    public Button getRightTall() {
+        return mRightTall;
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.HORIZONTAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+        mLeftTall = makeTall("left tall");
+        mLayout.addView(mLeftTall);
+
+        mMidShort1Top = addShort(mLayout, "mid(1) top", false);
+        mMidShort2Bottom = addShort(mLayout, "mid(2) bottom", true);
+
+        mRightTall = makeTall("right tall");
+        mLayout.addView(mRightTall);
+
+        setContentView(mLayout);
+    }
+
+    // just to get toString non-sucky
+    private static class MyButton extends Button {
+
+        public MyButton(Context context) {
+            super(context);
+        }
+
+
+        @Override
+        public String toString() {
+            return getText().toString();
+        }
+    }
+
+    private Button makeTall(String label) {
+        Button button = new MyButton(this);
+        button.setText(label);
+        button.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        return button;
+    }
+
+    private Button addShort(LinearLayout root, String label, boolean atBottom) {
+        Button button = new MyButton(this);
+        button.setText(label);
+        button.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                0, // height
+                490));
+
+        TextView filler = new TextView(this);
+        filler.setText("filler");
+        filler.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                0, // height
+                510));
+
+        LinearLayout ll = new LinearLayout(this);
+        ll.setOrientation(LinearLayout.VERTICAL);
+        ll.setLayoutParams(new LinearLayout.LayoutParams(
+            ViewGroup.LayoutParams.WRAP_CONTENT,
+            ViewGroup.LayoutParams.FILL_PARENT));
+
+        if (atBottom) {
+            ll.addView(filler);
+            ll.addView(button);
+            root.addView(ll);
+        } else {
+            ll.addView(button);
+            ll.addView(filler);
+            root.addView(ll);
+        }
+        return button;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/LinearLayoutGrid.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/LinearLayoutGrid.java
new file mode 100644
index 0000000..9aec0d5
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/LinearLayoutGrid.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import com.android.frameworktest.R;
+
+public class LinearLayoutGrid extends Activity {
+
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.linear_layout_grid);
+    }
+
+    public ViewGroup getRootView() {
+        return (ViewGroup) findViewById(R.id.layout);
+    }
+
+    public Button getButtonAt(int column, int row) {
+        if (row < 0 || row > 2) {
+            throw new IllegalArgumentException("row out of range");
+        }
+        if (column < 0 || column > 2) {
+            throw new IllegalArgumentException("column out of range");
+        }
+        return (Button) getColumn(column).getChildAt(row);
+    }
+
+
+
+    private LinearLayout getColumn(int column) {
+        switch (column) {
+            case 0:
+                return (LinearLayout) findViewById(R.id.column1);
+            case 1:
+                return (LinearLayout) findViewById(R.id.column2);
+            case 2:
+                return (LinearLayout) findViewById(R.id.column3);
+            default:
+                throw new IllegalArgumentException("column out of range");
+        }
+    }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfButtons.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfButtons.java
new file mode 100644
index 0000000..0abcebb
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfButtons.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+
+/**
+ * A layout with a ListView containing buttons.
+ */
+public class ListOfButtons extends ListActivity {
+
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_with_button_above);
+        getListView().setItemsCanFocus(true);
+        setListAdapter(new MyAdapter(this, mLabels));
+    }
+
+    String[] mLabels = {
+            "Alabama", "Alaska", "Arizona", "apple sauce!",
+            "California", "Colorado", "Connecticut", "Delaware"
+    };
+
+
+    public String[] getLabels() {
+        return mLabels;
+    }
+
+    public static class MyAdapter extends ArrayAdapter<String> {
+
+
+        public MyAdapter(Context context, String[] labels) {
+            super(context, 0, labels);
+        }
+
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            String label = getItem(position);
+
+            Button button = new Button(parent.getContext());
+            button.setText(label);
+            return button;
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfEditTexts.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfEditTexts.java
new file mode 100644
index 0000000..f59e2b7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfEditTexts.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+import com.google.android.collect.Lists;
+
+import java.util.List;
+
+public class ListOfEditTexts extends Activity {
+
+    private int mLinesPerEditText = 12;
+
+    private ListView mListView;
+    private LinearLayout mLinearLayout;
+
+    public ListView getListView() {
+        return mListView;
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // create linear layout
+        mLinearLayout = new LinearLayout(this);
+        mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+        mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+        // add a button above
+        Button buttonAbove = new Button(this);
+        buttonAbove.setLayoutParams(
+                new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.FILL_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT));
+        buttonAbove.setText("button above list");
+        mLinearLayout.addView(buttonAbove);
+
+        // add a list view to it
+        mListView = new ListView(this);
+        mListView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        mListView.setDrawSelectorOnTop(false);
+        mListView.setItemsCanFocus(true);
+        mListView.setLayoutParams((new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                0,
+                1f)));
+
+        List<String> bodies = Lists.newArrayList(
+                getBody("zero hello, my name is android"),
+                getBody("one i'm a paranoid android"),
+                getBody("two i robot.  huh huh."),
+                getBody("three not the g-phone!"));
+
+        mListView.setAdapter(new MyAdapter(this, bodies));
+        mLinearLayout.addView(mListView);
+
+        // add button below
+        Button buttonBelow = new Button(this);
+        buttonBelow.setLayoutParams(
+                new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.FILL_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT));
+        buttonBelow.setText("button below list");
+        mLinearLayout.addView(buttonBelow);
+        
+        setContentView(mLinearLayout);
+    }
+
+    String getBody(String line) {
+        StringBuilder sb = new StringBuilder((line.length() + 5) * mLinesPerEditText);
+        for (int i = 0; i < mLinesPerEditText; i++) {
+            sb.append(i + 1).append(' ').append(line);
+            if (i < mLinesPerEditText - 1) {
+                sb.append('\n'); // all but last line
+            }
+        }
+        return sb.toString();
+    }
+
+
+    private static class MyAdapter extends ArrayAdapter<String> {
+
+        public MyAdapter(Context context, List<String> bodies) {
+            super(context, 0, bodies);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            String body = getItem(position);
+
+            if (convertView != null) {
+                ((EditText) convertView).setText(body);
+                return convertView;                
+            }
+
+            EditText editText = new EditText(getContext());
+            editText.setText(body);
+            return editText;
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfInternalSelectionViews.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfInternalSelectionViews.java
new file mode 100644
index 0000000..4bbca74
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfInternalSelectionViews.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import com.android.frameworktest.util.InternalSelectionView;
+
+/**
+ * A list of {@link InternalSelectionView}s paramatarized by the number of items,
+ * how many rows in each item, and how tall each item is.
+ */
+public class ListOfInternalSelectionViews extends Activity {
+
+    private ListView mListView;
+
+
+    // keys for initializing via Intent params
+    public static final String BUNDLE_PARAM_NUM_ITEMS = "com.google.test.numItems";
+    public static final String BUNDLE_PARAM_NUM_ROWS_PER_ITEM = "com.google.test.numRowsPerItem";
+    public static final String BUNDLE_PARAM_ITEM_SCREEN_HEIGHT_FACTOR = "com.google.test.itemScreenHeightFactor";
+
+    private int mScreenHeight;
+
+    private int mNumItems = 5;
+    private int mNumRowsPerItem = 4;
+    private double mItemScreenSizeFactor = 5 / 4;
+
+    public ListView getListView() {
+        return mListView;
+    }
+
+    /**
+     * Each item is screen height * this factor tall.
+     */
+    public double getItemScreenSizeFactor() {
+        return mItemScreenSizeFactor;
+    }
+
+    /**
+     * @return The number of rows per item.
+     */
+    public int getNumRowsPerItem() {
+        return mNumRowsPerItem;
+    }
+
+    /**
+     * @return The number of items in the list.
+     */
+    public int getNumItems() {
+        return mNumItems;
+    }
+
+    /**
+     * @param position The position
+     * @return The label (closest thing to a value) for the item at position
+     */
+    public String getLabelForPosition(int position) {
+        return "position " + position;
+    }
+
+    /**
+     * Get the currently selected view.
+     */
+    public InternalSelectionView getSelectedView() {
+        return (InternalSelectionView) getListView().getSelectedView();
+    }
+
+    /**
+     * Get the screen height.
+     */
+    public int getScreenHeight() {
+        return mScreenHeight;
+    }
+
+    /**
+     * Initialize a bundle suitable for sending as the params of the intent that
+     * launches this activity.
+     * @param numItems The number of items in the list.
+     * @param numRowsPerItem The number of rows per item.
+     * @param itemScreenHeightFactor see {@link #getScreenHeight()}
+     * @return the intialized bundle.
+     */
+    public static Bundle getBundleFor(int numItems, int numRowsPerItem, double itemScreenHeightFactor) {
+        Bundle bundle = new Bundle();
+        bundle.putInt(BUNDLE_PARAM_NUM_ITEMS, numItems);
+        bundle.putInt(BUNDLE_PARAM_NUM_ROWS_PER_ITEM, numRowsPerItem);
+        bundle.putDouble(BUNDLE_PARAM_ITEM_SCREEN_HEIGHT_FACTOR, itemScreenHeightFactor);
+        return bundle;
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+
+        Bundle extras = getIntent().getExtras();
+        if (extras != null) {
+            initFromBundle(extras);
+        }
+
+        mListView = new ListView(this);
+        mListView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        mListView.setDrawSelectorOnTop(false);
+        mListView.setAdapter(new MyAdapter());
+        mListView.setItemsCanFocus(true);
+        setContentView(mListView);
+    }
+
+    private void initFromBundle(Bundle icicle) {
+
+        int numItems = icicle.getInt(BUNDLE_PARAM_NUM_ITEMS, -1);
+        if (numItems != -1) {
+            mNumItems = numItems;
+        }
+        int numRowsPerItem = icicle.getInt(BUNDLE_PARAM_NUM_ROWS_PER_ITEM, -1);
+        if (numRowsPerItem != -1) {
+            mNumRowsPerItem = numRowsPerItem;
+        }
+        double screenHeightFactor = icicle.getDouble(BUNDLE_PARAM_ITEM_SCREEN_HEIGHT_FACTOR, -1.0);
+        if (screenHeightFactor > 0) {
+            mItemScreenSizeFactor = screenHeightFactor;
+        }
+    }
+
+    private class MyAdapter extends BaseAdapter {
+
+        public int getCount() {
+            return mNumItems;
+        }
+
+        public Object getItem(int position) {
+            return getLabelForPosition(position);
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            InternalSelectionView item =
+                    new InternalSelectionView(
+                            parent.getContext(),
+                            mNumRowsPerItem,
+                            getLabelForPosition(position));
+            item.setDesiredHeight((int) (mScreenHeight * mItemScreenSizeFactor));
+            return item;
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabels.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabels.java
new file mode 100644
index 0000000..730f9aa
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabels.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.google.android.collect.Lists;
+import com.android.frameworktest.R;
+
+import java.util.List;
+
+public class ListWithFooterViewAndNewLabels extends ListActivity {
+
+    private MyAdapter mMyAdapter;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_with_button_above);
+
+        Button footerButton = new Button(this);
+        footerButton.setText("hi");
+        footerButton.setLayoutParams(
+                new AbsListView.LayoutParams(
+                        ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT));
+        getListView().addFooterView(footerButton);
+
+        mMyAdapter = new MyAdapter(this);
+        setListAdapter(mMyAdapter);
+
+        // not in list
+        Button topButton = (Button) findViewById(R.id.button);
+        topButton.setText("click to add new item");
+        topButton.setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                mMyAdapter.addLabel("yo");
+            }
+        });
+
+        mMyAdapter.addLabel("first");
+    }
+
+    /**
+     * An adapter that can take new string labels.
+     */
+    static class MyAdapter extends BaseAdapter {
+
+        private final Context mContext;
+        private List<String> mLabels = Lists.newArrayList();
+
+        public MyAdapter(Context context) {
+            mContext = context;
+        }
+
+        public int getCount() {
+            return mLabels.size();
+        }
+
+        public Object getItem(int position) {
+            return mLabels.get(position);
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            String label = mLabels.get(position);
+
+            LayoutInflater inflater = (LayoutInflater)
+                    mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+            TextView tv = (TextView) inflater.inflate(
+                    android.R.layout.simple_list_item_1,
+                    null);
+            tv.setText(label);
+            return tv;
+        }
+
+        public void addLabel(String s) {
+            mLabels.add(s + mLabels.size());
+            notifyDataSetChanged();
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithMailMessages.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithMailMessages.java
new file mode 100644
index 0000000..27c642a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithMailMessages.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.R;
+import com.google.android.collect.Lists;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.webkit.WebView;
+
+import java.util.List;
+
+public class ListWithMailMessages extends ListActivity {
+
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.list_with_button_above);
+
+        List<MailMessage> messages = Lists.newArrayList();
+        messages.add(new MailMessage("hello!", "<p>this is a test "
+                + "message, with a bunch of text and stuff.</p>", true));
+
+//        String android = "android";
+        String android = "<a href=\"www.android.com\">android</a>";
+
+        String sentance = "all work and no play makes "
+        + android + " a dull... robot!";
+        StringBuffer longBody = new StringBuffer().append("<ol>\n");
+        for (int i = 0; i < 12; i++) {
+            longBody.append("<li>").append(sentance).append("</li>");
+        }
+        longBody.append("</ol>");
+
+        messages.add(new MailMessage("hello2!", longBody.toString(), true));
+        messages.add(new MailMessage("phone number?", "<p>hey man, what's ur "
+                + "contact info? i need to mail you this photo of my two"
+                + " cats, they've gotten soooo fat!</p>", true));
+
+        setListAdapter(new MyAdapter(this, R.layout.mail_message, messages));
+        getListView().setItemsCanFocus(true);
+    }
+
+
+    /**
+     * POJO mail message.
+     */
+    static class MailMessage {
+        private String mSubject;
+        private String mBody;
+        private boolean mFocusable;
+
+
+        public MailMessage(String subject, String body) {
+            this(subject, body, false);
+        }
+
+
+        public MailMessage(String subject, String body, boolean focusable) {
+            mSubject = subject;
+            mBody = body;
+            mFocusable = focusable;
+        }
+
+        public String getSubject() {
+            return mSubject;
+        }
+
+        public void setSubject(String subject) {
+            this.mSubject = subject;
+        }
+
+        public String getBody() {
+            return mBody;
+        }
+
+        public void setBody(String body) {
+            this.mBody = body;
+        }
+
+
+        public boolean isFocusable() {
+            return mFocusable;
+        }
+
+        public void setFocusable(boolean focusable) {
+            mFocusable = focusable;
+        }
+    }
+
+
+    public static class MyAdapter extends ArrayAdapter<MailMessage> {
+
+        public MyAdapter(Context context, int resource,
+                List<MailMessage> objects) {
+            super(context, resource, objects);
+        }
+
+        final String mimeType = "text/html";
+        final String encoding = "utf-8";
+
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            MailMessage message = getItem(position);
+
+            LayoutInflater inflater = (LayoutInflater)
+                    getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+            LinearLayout messageUi = (LinearLayout) inflater
+                    .inflate(R.layout.mail_message, null);
+
+            TextView subject = (TextView) messageUi.findViewById(R.id.subject);
+            subject.setText(message.getSubject());
+
+            WebView body = (WebView) messageUi.findViewById(R.id.body);
+            body.loadData(message.getBody(), mimeType, encoding);
+//            body.setText(message.getBody());
+            body.setFocusable(message.isFocusable());
+
+            return messageUi;
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/RequestFocus.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/RequestFocus.java
new file mode 100644
index 0000000..803815b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/RequestFocus.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.view.View;
+
+/**
+ * Exercises cases where elements of the UI are requestFocus()ed.
+ */
+public class RequestFocus extends Activity {
+    protected final Handler mHandler = new Handler();
+
+    @Override protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.focus_after_removal);
+
+        // bottom right button starts with the focus.
+        final Button bottomRightButton = (Button) findViewById(R.id.bottomRightButton);
+        bottomRightButton.requestFocus();
+        bottomRightButton.setText("I should have focus");
+    }
+
+    public Handler getHandler() {
+        return mHandler;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/VerticalFocusSearch.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/VerticalFocusSearch.java
new file mode 100644
index 0000000..d1b83a3
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/VerticalFocusSearch.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.TextView;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.content.Context;
+
+/**
+ * Holds a few buttons of various sizes and horizontal placements in a
+ * vertical layout to excercise some core focus searching.
+ */
+public class VerticalFocusSearch extends Activity {
+
+    private LinearLayout mLayout;
+
+    private Button mTopWide;
+    private Button mMidSkinny1Left;
+    private Button mBottomWide;
+
+    private Button mMidSkinny2Right;
+
+
+    public LinearLayout getLayout() {
+        return mLayout;
+    }
+
+    public Button getTopWide() {
+        return mTopWide;
+    }
+
+    public Button getMidSkinny1Left() {
+        return mMidSkinny1Left;
+    }
+
+    public Button getMidSkinny2Right() {
+        return mMidSkinny2Right;
+    }
+
+    public Button getBottomWide() {
+        return mBottomWide;
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        mLayout.setHorizontalGravity(Gravity.LEFT);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+        mTopWide = makeWide("top wide");
+        mLayout.addView(mTopWide);
+
+        mMidSkinny1Left = addSkinny(mLayout, "mid skinny 1(L)", false);
+
+        mMidSkinny2Right = addSkinny(mLayout, "mid skinny 2(R)", true);
+
+        mBottomWide = makeWide("bottom wide");
+        mLayout.addView(mBottomWide);
+
+        setContentView(mLayout);
+    }
+
+    // just to get toString non-sucky
+    private static class MyButton extends Button {
+
+        public MyButton(Context context) {
+            super(context);
+        }
+
+
+        @Override
+        public String toString() {
+            return getText().toString();
+        }
+    }
+
+    private Button makeWide(String label) {
+        Button button = new MyButton(this);
+        button.setText(label);
+        button.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        return button;
+    }
+
+    /**
+     * Add a skinny button that takes up just less than half of the screen
+     * horizontally.
+     * @param root The layout to add the button to.
+     * @param label The label of the button.
+     * @param atRight Which side to put the button on.
+     * @return The newly created button.
+     */
+    private Button addSkinny(LinearLayout root, String label, boolean atRight) {
+        Button button = new MyButton(this);
+        button.setText(label);
+        button.setLayoutParams(new LinearLayout.LayoutParams(
+                0, // width
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                480));
+
+        TextView filler = new TextView(this);
+        filler.setText("filler");
+        filler.setLayoutParams(new LinearLayout.LayoutParams(
+                0, // width
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                520));
+
+        LinearLayout ll = new LinearLayout(this);
+        ll.setOrientation(LinearLayout.HORIZONTAL);
+        ll.setLayoutParams(new LinearLayout.LayoutParams(
+            ViewGroup.LayoutParams.FILL_PARENT,
+            ViewGroup.LayoutParams.WRAP_CONTENT));
+
+        if (atRight) {
+            ll.addView(filler);
+            ll.addView(button);
+            root.addView(ll);
+        } else {
+            ll.addView(button);
+            ll.addView(filler);
+            root.addView(ll);
+        }
+        return button;
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridDelete.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridDelete.java
new file mode 100644
index 0000000..4c0d23b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridDelete.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.ListAdapter;
+
+import com.android.frameworktest.util.GridScenario;
+
+import java.util.ArrayList;
+
+/**
+ * A grid with vertical spacing between rows
+ */
+public class GridDelete extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(1001)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.20)
+                .setVerticalSpacing(20);
+    }
+    
+    
+    
+    @Override
+    protected ListAdapter createAdapter() {
+        return new DeleteAdapter(getInitialNumItems());
+    }
+
+    
+    
+    
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_DEL) {
+            GridView g = getGridView();
+            ((DeleteAdapter)g.getAdapter()).deletePosition(g.getSelectedItemPosition());
+            return true;
+        } else {
+            return super.onKeyDown(keyCode, event);
+        }
+    }
+
+
+
+
+    private class DeleteAdapter extends BaseAdapter {
+        
+        private ArrayList<Integer> mData;
+        
+        public DeleteAdapter(int initialNumItems) {
+            super();
+            mData = new ArrayList<Integer>(initialNumItems);
+            
+            int i;
+            for (i=0; i<initialNumItems; ++i) {
+                mData.add(new Integer(10000 + i));
+            }
+            
+        }
+
+        public void deletePosition(int selectedItemPosition) {
+            if (selectedItemPosition >=0 && selectedItemPosition < mData.size()) {
+                mData.remove(selectedItemPosition);
+                notifyDataSetChanged();
+            }
+            
+        }
+
+        public int getCount() {
+            return mData.size();
+        }
+
+        public Object getItem(int position) {
+            return mData.get(position);
+        }
+
+        public long getItemId(int position) {
+            return mData.get(position);
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            int desiredHeight = getDesiredItemHeight();
+            return createView(mData.get(position), parent, desiredHeight);
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInHorizontal.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInHorizontal.java
new file mode 100644
index 0000000..c10a53b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInHorizontal.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a grid in a horizontal linear layout
+ */
+public class GridInHorizontal extends Activity {
+    Handler mHandler = new Handler();
+    TextView mText;
+    GridView mGridView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        setContentView(R.layout.grid_in_horizontal);
+
+        String values[] = new String[1000];
+        int i=0;
+        for(i=0; i<1000; i++) {
+            values[i] = ((Integer)i).toString();
+        }
+        
+        mText = (TextView) findViewById(R.id.text);
+        mGridView = (GridView) findViewById(R.id.grid);
+        mGridView.setAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+
+    }
+    
+    public GridView getGridView() {
+        return mGridView;
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInVertical.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInVertical.java
new file mode 100644
index 0000000..acde73e
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInVertical.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a grid in a vertical linear layout
+ */
+public class GridInVertical extends Activity {
+    Handler mHandler = new Handler();
+    TextView mText;
+    GridView mGridView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        setContentView(R.layout.grid_in_vertical);
+
+        String values[] = new String[1000];
+        int i=0;
+        for(i=0; i<1000; i++) {
+            values[i] = ((Integer)i).toString();
+        }
+        
+        mText = (TextView) findViewById(R.id.text);
+        mGridView = (GridView) findViewById(R.id.grid);
+        mGridView.setAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+
+    }
+    
+    public GridView getGridView() {
+        return mGridView;
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridPadding.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridPadding.java
new file mode 100644
index 0000000..41909ac2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridPadding.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a grid with padding
+ */
+public class GridPadding extends Activity {
+    private GridView mGridView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.grid_padding);
+
+        String values[] = new String[1000];
+        for(int i = 0; i < 1000; i++) {
+            values[i] = String.valueOf(i);
+        }
+
+        mGridView = (GridView) findViewById(R.id.grid);
+        mGridView.setAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+    }
+
+    public GridView getGridView() {
+        return mGridView;
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridScrollListener.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridScrollListener.java
new file mode 100644
index 0000000..4655230
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridScrollListener.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.AbsListView;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises change notification in a list
+ */
+public class GridScrollListener extends Activity implements AbsListView.OnScrollListener {
+    Handler mHandler = new Handler();
+    TextView mText;
+    GridView mGridView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        setContentView(R.layout.grid_scroll_listener);
+
+        String values[] = new String[1000];
+        int i=0;
+        for(i=0; i<1000; i++) {
+            values[i] = ((Integer)i).toString();
+        }
+        
+        mText = (TextView) findViewById(R.id.text);
+        mGridView = (GridView) findViewById(R.id.grid);
+        mGridView.setAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+
+        mGridView.setOnScrollListener(this);
+    }
+    
+    public GridView getGridView() {
+        return mGridView;
+    }
+
+    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+        int lastItem = firstVisibleItem + visibleItemCount - 1;
+        mText.setText("Showing " + firstVisibleItem + "-" + lastItem + "/" + totalItemCount);
+    }
+
+    public void onScrollStateChanged(AbsListView view, int scrollState) {        
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelection.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelection.java
new file mode 100644
index 0000000..38f629d
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelection.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic stacking from top scenario, nothing fancy. Items do not
+ * fill the screen.
+ */
+public class GridSetSelection extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(15)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.12);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionMany.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionMany.java
new file mode 100644
index 0000000..34aeb75
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionMany.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic stacking from top scenario, nothing fancy. Items do
+ * fill the screen.
+ */
+public class GridSetSelectionMany extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(150)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.12);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottom.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottom.java
new file mode 100644
index 0000000..6a2445f
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottom.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic stacking from bottom scenario, nothing fancy. Items do not
+ * fill the screen.
+ */
+public class GridSetSelectionStackFromBottom extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(true)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(15)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.12);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomMany.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomMany.java
new file mode 100644
index 0000000..838c431
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomMany.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic stacking from bottom scenario, nothing fancy. Items do
+ * fill the screen.
+ */
+public class GridSetSelectionStackFromBottomMany extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(true)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(150)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.12);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSimple.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSimple.java
new file mode 100644
index 0000000..f7f68f5
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSimple.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.gridview;
+
+import android.graphics.drawable.PaintDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.frameworktest.util.GridScenario;
+
+public class GridSimple extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setNumItems(1000)
+                .setNumColumns(3)
+                .setItemScreenSizeFactor(0.14);
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        getGridView().setSelector(new PaintDrawable(0xFFFF0000));
+        getGridView().setPadding(0, 0, 0, 0);
+        getGridView().setFadingEdgeLength(64);
+        getGridView().setVerticalFadingEdgeEnabled(true);
+        getGridView().setBackgroundColor(0xFFC0C0C0);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        View view = super.createView(position, parent, desiredHeight);
+        view.setBackgroundColor(0xFF000000);
+        ((TextView) view).setTextSize(16.0f);
+        return view;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSingleColumn.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSingleColumn.java
new file mode 100644
index 0000000..a909bd8
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSingleColumn.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+import android.widget.GridView;
+
+/**
+ * A grid with vertical spacing between rows
+ */
+public class GridSingleColumn extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(101)
+                .setNumColumns(1)
+                .setColumnWidth(60)
+                .setItemScreenSizeFactor(0.20)
+                .setVerticalSpacing(20)
+                .setStretchMode(GridView.STRETCH_SPACING);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottom.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottom.java
new file mode 100644
index 0000000..304110e
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottom.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic bottom stacking from bottom scenario, nothing fancy. Items do not
+ * fill the screen
+ */
+public class GridStackFromBottom extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(true)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(15)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.12);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottomMany.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottomMany.java
new file mode 100644
index 0000000..94d801e
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottomMany.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic bottom stacking from bottom scenario, nothing fancy. The grid items do not fit on the
+ * screen (to exercise scrolling.)
+ */
+public class GridStackFromBottomMany extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(true)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(54)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.12);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridThrasher.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridThrasher.java
new file mode 100644
index 0000000..d628f2d
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridThrasher.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+import java.util.Random;
+
+/**
+ * Exercises change notification in a list
+ */
+public class GridThrasher extends Activity implements AdapterView.OnItemSelectedListener
+{
+    Handler mHandler = new Handler();
+    ThrashListAdapter mAdapter;
+    Random mRandomizer = new Random();
+    TextView mText;
+    
+    Runnable mThrash = new Runnable() {
+        public void run() {
+            mAdapter.bumpVersion();
+            mHandler.postDelayed(mThrash, 500);
+        }
+    };
+
+    private class ThrashListAdapter extends BaseAdapter {
+        private LayoutInflater mInflater;
+        
+        /**
+         * Our data, part 1.
+         */
+        private String[] mTitles = new String[100];
+        
+        /**
+         * Our data, part 2.
+         */
+        private int[] mVersion = new int[100];
+
+        public ThrashListAdapter(Context context) {
+            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            mTitles = new String[100];
+            mVersion = new int[100];
+            
+            int i;
+            for (i=0; i<100; i++) {
+                mTitles[i] = "[" + i + "]";
+                mVersion[i] = 0;
+            }
+        }
+
+        public int getCount() {
+            return mTitles.length;
+        }
+
+        public Object getItem(int position) {
+            return position;
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TextView view;
+
+            if (convertView == null) {
+                view = (TextView) mInflater.inflate(android.R.layout.simple_list_item_1, null);
+            } else {
+                view = (TextView) convertView;
+            }
+            view.setText(mTitles[position] + " " + mVersion[position]);
+            return view;
+        }
+
+        
+        public void bumpVersion() {
+            int position = mRandomizer.nextInt(getCount());
+            mVersion[position]++;
+            notifyDataSetChanged();
+        }
+             
+
+    }
+    
+    @Override
+    public void onCreate(Bundle icicle) 
+    {
+        super.onCreate(icicle);
+        
+        setContentView(R.layout.grid_thrasher);
+        
+        mText = (TextView) findViewById(R.id.text);
+        mAdapter = new ThrashListAdapter(this);
+        GridView g = (GridView) findViewById(R.id.grid);
+        g.setAdapter(mAdapter);
+        
+        mHandler.postDelayed(mThrash, 5000);
+        
+        g.setOnItemSelectedListener(this);
+    }
+
+    public void onItemSelected(AdapterView parent, View v, int position, long id) {
+        mText.setText("Position " + position);
+    }
+
+    public void onNothingSelected(AdapterView parent) {
+        mText.setText("Nothing");
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacing.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacing.java
new file mode 100644
index 0000000..3f6b8d6
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacing.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * A grid with vertical spacing between rows
+ */
+public class GridVerticalSpacing extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(101)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.20)
+                .setVerticalSpacing(20);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacingStackFromBottom.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacingStackFromBottom.java
new file mode 100644
index 0000000..1a39ffb
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacingStackFromBottom.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * A grid with vertical spacing between rows that stacks from the bottom
+ */
+public class GridVerticalSpacingStackFromBottom extends GridScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(true)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(101)
+                .setNumColumns(4)
+                .setItemScreenSizeFactor(0.20)
+                .setVerticalSpacing(20);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutGravity.java
new file mode 100644
index 0000000..1383dae
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutGravity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.frame;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class FrameLayoutGravity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.framelayout_gravity);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutMargin.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutMargin.java
new file mode 100644
index 0000000..0434726
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutMargin.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.frame;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class FrameLayoutMargin extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.framelayout_margin);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravity.java
new file mode 100644
index 0000000..5087c62
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class BaselineAlignmentCenterGravity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.baseline_center_gravity);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeight.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
new file mode 100644
index 0000000..3c1d7fd
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class BaselineAlignmentZeroWidthAndWeight extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.baseline_0width_and_weight);
+
+        findViewById(R.id.show).setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                findViewById(R.id.layout).setVisibility(View.VISIBLE);
+            }
+        });
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineButtons.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineButtons.java
new file mode 100644
index 0000000..9bb9bff
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineButtons.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class BaselineButtons extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.baseline_buttons);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/ExceptionTextView.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/ExceptionTextView.java
new file mode 100644
index 0000000..54f6b98
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/ExceptionTextView.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import junit.framework.Assert;
+
+import android.widget.EditText;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.text.BoringLayout;
+
+
+/**
+ * A special EditText that sets {@link #isFailed()} to true as its internal makeNewLayout() method is called
+ * with a width lower than 0. This is used to fail the unit test in
+ * BaselineAlignmentZeroWidthAndWeightTest.
+ */
+public class ExceptionTextView extends EditText {
+
+    private boolean mFailed = false;
+
+    public ExceptionTextView(Context context) {
+        super(context);
+    }
+
+    public ExceptionTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public ExceptionTextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public boolean isFailed() {
+        return mFailed;
+    }
+
+    @Override
+    protected void makeNewLayout(int w, int hintWidth,
+                                 BoringLayout.Metrics boring,
+                                 BoringLayout.Metrics hintMetrics,
+                                 int ellipsizedWidth, boolean bringIntoView) {
+        if (w < 0) {
+            mFailed = true;
+            w = 100;
+        }
+
+        super.makeNewLayout(w, hintWidth, boring, hintMetrics, ellipsizedWidth,
+                            bringIntoView);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/FillInWrap.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/FillInWrap.java
new file mode 100644
index 0000000..a95cf17
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/FillInWrap.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class FillInWrap extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.fill_in_wrap);
+        ((TextView) findViewById(R.id.data)).setText("1\n2\n3\n4\n5");
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/HorizontalOrientationVerticalAlignment.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/HorizontalOrientationVerticalAlignment.java
new file mode 100644
index 0000000..1308b8b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/HorizontalOrientationVerticalAlignment.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class HorizontalOrientationVerticalAlignment extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.linear_layout_spinner_then_button);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLEditTextThenButton.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLEditTextThenButton.java
new file mode 100644
index 0000000..db868cb
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLEditTextThenButton.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+public class LLEditTextThenButton extends Activity {
+    private EditText mEditText;
+    private Button mButton;
+
+    private LinearLayout mLayout;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.linear_layout_edittext_then_button);
+
+        mLayout = (LinearLayout) findViewById(R.id.layout);
+        mEditText = (EditText) findViewById(R.id.editText);
+        mButton = (Button) findViewById(R.id.button);
+    }
+
+    public LinearLayout getLayout() {
+        return mLayout;
+    }
+
+    public EditText getEditText() {
+        return mEditText;
+    }
+
+    public Button getButton() {
+        return mButton;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons1.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons1.java
new file mode 100644
index 0000000..33189e5
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons1.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import com.android.frameworktest.R;
+
+/**
+ * One of two simple vertical linear layouts of buttons used to test out
+ * the transistion between touch and focus mode.
+ */
+public class LLOfButtons1 extends Activity {
+
+    private boolean mButtonPressed = false;
+    private Button mFirstButton;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.linear_layout_buttons);
+        mFirstButton = (Button) findViewById(R.id.button1);
+
+        mFirstButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mButtonPressed = true;
+            }
+        });
+
+    }
+
+    public LinearLayout getLayout() {
+        return (LinearLayout) findViewById(R.id.layout);
+    }
+
+    public Button getFirstButton() {
+        return mFirstButton;
+    }
+
+    public boolean buttonClickListenerFired() {
+        return mButtonPressed;
+    }
+
+    public boolean isInTouchMode() {
+        return mFirstButton.isInTouchMode();
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons2.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons2.java
new file mode 100644
index 0000000..1e0c97a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons2.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+/**
+ * One of two simple vertical linear layouts of buttons used to test out
+ * the transistion between touch and focus mode.
+ */
+public class LLOfButtons2  extends LLOfButtons1 {
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfTwoFocusableInTouchMode.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfTwoFocusableInTouchMode.java
new file mode 100644
index 0000000..201c8f9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfTwoFocusableInTouchMode.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class LLOfTwoFocusableInTouchMode extends Activity {
+
+    private View mButton1;
+    private View mButton2;
+    private View mButton3;
+
+    private boolean mB1Fired = false;
+    private boolean mB2Fired = false;
+    private boolean mB3Fired = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.linear_layout_buttons);
+
+        mButton1 = findViewById(R.id.button1);
+        mButton2 = findViewById(R.id.button2);
+        mButton3 = findViewById(R.id.button3);
+
+        mButton1.setFocusableInTouchMode(true);
+        mButton2.setFocusableInTouchMode(true);
+        mButton3.setFocusableInTouchMode(true);
+
+        mButton1.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mB1Fired = true;
+            }
+        });
+
+        mButton2.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mB2Fired = true;
+            }
+        });
+
+        mButton3.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mB3Fired = true;
+            }
+        });
+    }
+
+    public View getButton1() {
+        return mButton1;
+    }
+
+    public View getButton2() {
+        return mButton2;
+    }
+
+    public View getButton3() {
+        return mButton3;
+    }
+
+    public boolean isB1Fired() {
+        return mB1Fired;
+    }
+
+    public boolean isB2Fired() {
+        return mB2Fired;
+    }
+
+    public boolean isB3Fired() {
+        return mB3Fired;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LinearLayoutEditTexts.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LinearLayoutEditTexts.java
new file mode 100644
index 0000000..4877a63
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LinearLayoutEditTexts.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class LinearLayoutEditTexts extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.linear_layout_textviews);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/Weight.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/Weight.java
new file mode 100644
index 0000000..0535f00
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/Weight.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Weight extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.linear_layout_weight);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/WeightSum.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/WeightSum.java
new file mode 100644
index 0000000..8b9a497
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/WeightSum.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class WeightSum extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.weight_sum);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/AddColumn.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/AddColumn.java
new file mode 100644
index 0000000..c490e0f
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/AddColumn.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+/**
+ * This test adds an extra row with an extra column in the table.
+ */
+public class AddColumn extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.add_column_in_table);
+
+        final Button addRowButton = (Button) findViewById(R.id.add_row_button);
+        addRowButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                final TableLayout table = (TableLayout) findViewById(R.id.table);
+                final TableRow newRow = new TableRow(AddColumn.this);
+                for (int i = 0; i < 4; i++) {
+                    final TextView view = new TextView(AddColumn.this);
+                    view.setText("Column " + (i + 1));
+                    view.setPadding(3, 3, 3, 3);
+                    newRow.addView(view, new TableRow.LayoutParams());
+                }
+                table.addView(newRow, new TableLayout.LayoutParams());
+                newRow.requestLayout();
+            }
+        });
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/CellSpan.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/CellSpan.java
new file mode 100644
index 0000000..243efc7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/CellSpan.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells spanning.
+ */
+public class CellSpan extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.table_layout_cell_span);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/FixedWidth.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/FixedWidth.java
new file mode 100644
index 0000000..2e2defc
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/FixedWidth.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells having a fixed width and height.
+ */
+public class FixedWidth extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.table_layout_fixed_width);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/HorizontalGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/HorizontalGravity.java
new file mode 100644
index 0000000..fdafa12
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/HorizontalGravity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells using a horizontal gravity.
+ */
+public class HorizontalGravity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.table_layout_horizontal_gravity);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/VerticalGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/VerticalGravity.java
new file mode 100644
index 0000000..1f161d9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/VerticalGravity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells using a vertical gravity.
+ */
+public class VerticalGravity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.table_layout_vertical_gravity);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/Weight.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/Weight.java
new file mode 100644
index 0000000..4c3835f
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/Weight.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells having a weight.
+ */
+public class Weight extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.table_layout_weight);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/AdjacentListsWithAdjacentISVsInside.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/AdjacentListsWithAdjacentISVsInside.java
new file mode 100644
index 0000000..5c38ef0
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/AdjacentListsWithAdjacentISVsInside.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+
+/**
+ * Most bodacious scenario yet!
+ */
+public class AdjacentListsWithAdjacentISVsInside extends Activity {
+
+    private ListView mLeftListView;
+    private ListView mRightListView;
+
+    public ListView getLeftListView() {
+        return mLeftListView;
+    }
+
+    public ListView getRightListView() {
+        return mRightListView;
+    }
+
+    public InternalSelectionView getLeftIsv() {
+        return (InternalSelectionView)
+                ((ViewGroup) mLeftListView.getChildAt(0)).getChildAt(0);
+    }
+
+    public InternalSelectionView getLeftMiddleIsv() {
+        return (InternalSelectionView)
+                ((ViewGroup) mLeftListView.getChildAt(0)).getChildAt(1);
+    }
+
+    public InternalSelectionView getRightMiddleIsv() {
+        return (InternalSelectionView)
+                ((ViewGroup) mRightListView.getChildAt(0)).getChildAt(0);
+    }
+
+    public InternalSelectionView getRightIsv() {
+        return (InternalSelectionView)
+                ((ViewGroup) mRightListView.getChildAt(0)).getChildAt(1);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final int desiredHeight = (int) (0.8 * getWindowManager().getDefaultDisplay().getHeight());
+
+        mLeftListView = new ListView(this);
+        mLeftListView.setAdapter(new AdjacentISVAdapter(desiredHeight));
+        mLeftListView.setItemsCanFocus(true);
+
+
+        mRightListView = new ListView(this);
+        mRightListView.setAdapter(new AdjacentISVAdapter(desiredHeight));
+        mRightListView.setItemsCanFocus(true);
+
+
+
+        setContentView(combineAdjacent(mLeftListView, mRightListView));
+    }
+
+    private static View combineAdjacent(View... views) {
+        if (views.length < 2) {
+            throw new IllegalArgumentException("you should pass at least 2 views in");
+        }
+
+        final LinearLayout ll = new LinearLayout(views[0].getContext());
+        ll.setOrientation(LinearLayout.HORIZONTAL);
+        final LinearLayout.LayoutParams lp =
+                new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);
+
+        for (View view : views) {
+            ll.addView(view, lp);
+        }
+        return ll;
+    }
+
+    static class AdjacentISVAdapter extends BaseAdapter {
+
+        private final int mItemHeight;
+
+        AdjacentISVAdapter(int itemHeight) {
+            mItemHeight = itemHeight;
+        }
+
+        public int getCount() {
+            return 1;
+        }
+
+        public Object getItem(int position) {
+            return position;
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final InternalSelectionView isvLeft = new InternalSelectionView(
+                    parent.getContext(), 5, "isv left");
+            isvLeft.setDesiredHeight(mItemHeight);
+            final InternalSelectionView isvRight = new InternalSelectionView(
+                    parent.getContext(), 5, "isv right");
+            isvRight.setDesiredHeight(mItemHeight);
+            return combineAdjacent(isvLeft, isvRight);
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravity.java
new file mode 100644
index 0000000..e729d52
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.view.Gravity;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic bottom gravity scenario, nothing fancy. Items do not
+ * fill the screen
+ */
+public class ListBottomGravity extends ListScenario {
+
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(true)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(2)
+                .setItemScreenSizeFactor(0.22);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravityMany.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravityMany.java
new file mode 100644
index 0000000..1225b9a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravityMany.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.view.Gravity;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic bottom gravity scenario, nothing fancy. There are
+ * more items than fit on the screen
+ */
+public class ListBottomGravityMany extends ListScenario {
+
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(true)
+                .setStartingSelectionPosition(-1)
+                .setNumItems(10)
+                .setItemScreenSizeFactor(0.22);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListButtonsDiagonalAcrossItems.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListButtonsDiagonalAcrossItems.java
new file mode 100644
index 0000000..bda2cd1
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListButtonsDiagonalAcrossItems.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListItemFactory;
+import static com.android.frameworktest.util.ListItemFactory.Slot;
+import com.android.frameworktest.util.ListScenario;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class ListButtonsDiagonalAcrossItems extends ListScenario {
+
+    @Override
+    protected void init(Params params) {
+        params.setItemsFocusable(true)
+                .setNumItems(3)
+                .setItemScreenSizeFactor(0.2)
+                .setMustFillScreen(false);
+    }
+
+    public Button getLeftButton() {
+        return (Button) ((ViewGroup) getListView().getChildAt(0)).getChildAt(0);
+    }
+
+    public Button getCenterButton() {
+        return (Button) ((ViewGroup) getListView().getChildAt(1)).getChildAt(1);
+    }
+
+    public Button getRightButton() {
+        return (Button) ((ViewGroup) getListView().getChildAt(2)).getChildAt(2);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent,
+            int desiredHeight) {
+        final Slot slot = position == 0 ? Slot.Left :
+                (position == 1 ? Slot.Middle : Slot.Right);
+        return ListItemFactory.horizontalButtonSlots(
+                parent.getContext(), desiredHeight, slot);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListDividers.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListDividers.java
new file mode 100644
index 0000000..62045d8
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListDividers.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a list width dividers and padding.
+ */
+public class ListDividers extends Activity {
+    private ListView mListView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_dividers);
+
+        String values[] = new String[1000];
+        for (int i = 0; i < 1000; i++) {
+            values[i] = ((Integer) i).toString();
+        }
+
+        mListView = (ListView) findViewById(android.R.id.list);
+        mListView.setAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+
+    }
+
+    public ListView getListView() {
+        return mListView;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListEndingWithMultipleSeparators.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListEndingWithMultipleSeparators.java
new file mode 100644
index 0000000..4ab1eef6
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListEndingWithMultipleSeparators.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListEndingWithMultipleSeparators extends ListScenario {
+
+    protected void init(Params params) {
+        params.setItemsFocusable(false)
+                .setNumItems(5)
+                .setItemScreenSizeFactor(0.22)
+                .setPositionUnselectable(3)
+                .setPositionUnselectable(4);
+    }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListFilter.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListFilter.java
new file mode 100644
index 0000000..b164d86
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListFilter.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+
+import com.android.frameworktest.R;
+
+
+/**
+ * Tests hiding and showing the list filter by hiding and showing an ancestor of the 
+ * ListView
+ */
+public class ListFilter extends ListActivity implements OnClickListener {
+
+    private View mFrame;
+    private Button mHide;
+    private Button mShow;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.list_filter);
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, mStrings));
+        getListView().setTextFilterEnabled(true);
+        mFrame = findViewById(R.id.frame);
+        
+        mHide = (Button) findViewById(R.id.hide);
+        mHide.setOnClickListener(this);
+        
+        mShow = (Button) findViewById(R.id.show);
+        mShow.setOnClickListener(this);
+    }
+    
+
+    public void onClick(View v) {
+        mFrame.setVisibility(v == mHide ? View.INVISIBLE : View.VISIBLE);
+    }
+
+    private String[] mStrings = {
+            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
+            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
+            "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
+            "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
+            "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
+            "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
+            "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
+            "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
+            "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
+            "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
+            "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
+            "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
+            "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
+            "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
+            "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
+            "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
+            "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
+            "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
+            "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
+            "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
+            "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
+            "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
+            "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
+            "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
+            "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
+            "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
+            "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
+            "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
+            "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
+            "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
+            "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
+            "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
+            "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
+            "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
+            "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
+            "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
+            "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
+            "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
+            "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
+            "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
+            "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
+            "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
+            "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
+            "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
+            "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
+            "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
+            "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
+            "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
+            "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
+            "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
+            "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
+            "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
+            "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
+            "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
+            "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
+            "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
+            "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
+            "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
+            "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
+            "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
+            "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
+            "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
+            "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
+            "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
+            "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
+            "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
+            "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
+            "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
+            "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
+            "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
+            "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
+            "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
+            "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
+            "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
+            "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
+            "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
+            "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
+            "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
+            "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
+            "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
+            "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
+            "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
+            "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
+            "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
+            "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
+            "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
+            "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
+            "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
+            "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
+            "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
+            "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
+            "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
+            "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
+            "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
+            "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
+            "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
+            "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
+            "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
+            "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
+            "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
+            "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
+            "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
+            "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
+            "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
+            "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
+            "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
+            "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
+            "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
+            "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
+            "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
+            "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
+            "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
+            "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
+            "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
+            "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
+            "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
+            "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
+            "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
+            "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
+            "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
+            "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
+            "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
+            "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
+            "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
+            "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
+            "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
+            "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
+            "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
+            "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
+            "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"};
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListGetSelectedView.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListGetSelectedView.java
new file mode 100644
index 0000000..28fa21a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListGetSelectedView.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic top gravity scenario. This test is made to check that getSelectedView() will return
+ * null in touch mode.
+ */
+public class ListGetSelectedView extends ListScenario {
+    @Override
+    protected void init(Params params) {
+        params.setMustFillScreen(false).setNumItems(2).setItemScreenSizeFactor(0.22);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHeterogeneous.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHeterogeneous.java
new file mode 100644
index 0000000..93abd78
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHeterogeneous.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.frameworktest.util.ListItemFactory;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * List that has different view types
+ */
+public class ListHeterogeneous extends ListScenario {
+
+    @Override
+    protected void init(Params params) {
+        params.setNumItems(50)
+                .setItemScreenSizeFactor(1.0 / 8)
+                .setItemsFocusable(true)
+                .setHeaderViewCount(3)
+                .setFooterViewCount(2);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        switch (position % 3) {
+        case 0:
+            return ListItemFactory.text(
+                    position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+        case 1:
+            return ListItemFactory.button(
+                    position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+        case 2:
+            return ListItemFactory.doubleText(
+                    position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+        }
+        
+        return null;
+    }
+
+    @Override
+    public View convertView(int position, View convertView, ViewGroup parent) {
+        switch (position % 3) {
+        case 0:
+            return ListItemFactory.convertText(convertView, getValueAtPosition(position), position);
+        case 1:
+            return ListItemFactory.convertButton(convertView, getValueAtPosition(position),
+                    position);
+        case 2:
+            return ListItemFactory.convertDoubleText(convertView, getValueAtPosition(position),
+                    position);
+        }
+
+        return null;
+    }
+    
+    @Override
+    public int getItemViewType(int position) {
+        return position % 3;
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        return 3;
+    }
+    
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHorizontalFocusWithinItemWins.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHorizontalFocusWithinItemWins.java
new file mode 100644
index 0000000..c5e1e97
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHorizontalFocusWithinItemWins.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListItemFactory;
+import static com.android.frameworktest.util.ListItemFactory.Slot;
+import com.android.frameworktest.util.ListScenario;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class ListHorizontalFocusWithinItemWins extends ListScenario {
+
+    @Override
+    protected void init(Params params) {
+        params.setItemsFocusable(true)
+                .setNumItems(2)
+                .setItemScreenSizeFactor(0.2)
+                .setMustFillScreen(false);
+    }
+
+    public Button getTopLeftButton() {
+        return (Button) ((ViewGroup) getListView().getChildAt(0)).getChildAt(0);
+    }
+
+    public Button getTopRightButton() {
+        return (Button) ((ViewGroup) getListView().getChildAt(0)).getChildAt(2);
+    }
+
+    public Button getBottomMiddleButton() {
+        return (Button) ((ViewGroup) getListView().getChildAt(1)).getChildAt(1);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent,
+            int desiredHeight) {
+        final Context context = parent.getContext();
+        if (position == 0) {
+            return ListItemFactory.horizontalButtonSlots(
+                    context, desiredHeight, Slot.Left, Slot.Right);
+        } else if (position == 1) {
+            return ListItemFactory.horizontalButtonSlots(
+                    context, desiredHeight, Slot.Middle);
+        } else {
+            throw new IllegalArgumentException("expecting position 0 or 1");
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInHorizontal.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInHorizontal.java
new file mode 100644
index 0000000..2128746
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInHorizontal.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a list in a horizontal linear layout
+ */
+public class ListInHorizontal extends Activity {
+    private ListView mListView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_in_horizontal);
+
+        String values[] = new String[1000];
+        for (int i = 0; i < 1000; i++) {
+            values[i] = ((Integer) i).toString();
+        }
+
+        mListView = (ListView) findViewById(R.id.list);
+        mListView.setAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+
+    }
+
+    public ListView getListView() {
+        return mListView;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInVertical.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInVertical.java
new file mode 100644
index 0000000..f4c93c8
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInVertical.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a list in a vertical linear layout
+ */
+public class ListInVertical extends Activity {
+    private ListView mListView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_in_vertical);
+
+        String values[] = new String[1000];
+        for (int i = 0; i < 1000; i++) {
+            values[i] = ((Integer) i).toString();
+        }
+
+        mListView = (ListView) findViewById(R.id.list);
+        mListView.setAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+
+    }
+
+    public ListView getListView() {
+        return mListView;
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInterleaveFocusables.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInterleaveFocusables.java
new file mode 100644
index 0000000..e45297e
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInterleaveFocusables.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.view.View;
+ import android.view.ViewGroup;
+ import com.google.android.collect.Sets;
+ import com.android.frameworktest.util.ListScenario;
+ import com.android.frameworktest.util.ListItemFactory;
+
+ import java.util.Set;
+
+/**
+ * List that interleaves focusable items.
+ */
+public class ListInterleaveFocusables extends ListScenario {
+
+    private Set<Integer> mFocusablePositions = Sets.newHashSet(1, 3, 6);
+
+    @Override
+    protected void init(Params params) {
+        params.setNumItems(7)
+                .setItemScreenSizeFactor(1.0 / 8)
+                .setItemsFocusable(true)
+                .setMustFillScreen(false);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        if (mFocusablePositions.contains(position)) {
+            return ListItemFactory.button(
+                    position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+        } else {
+            return super.createView(position, parent, desiredHeight);
+        }
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return mFocusablePositions.contains(position) ? 0 : 1;
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        return 2;
+    }
+    
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusableAboveUnfocusable.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusableAboveUnfocusable.java
new file mode 100644
index 0000000..e14da5b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusableAboveUnfocusable.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import com.android.frameworktest.util.ListItemFactory;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list where the items may befocusable, but the second item isn't actually focusabe.
+ */
+public class ListItemFocusableAboveUnfocusable extends ListScenario {
+
+
+    protected void init(Params params) {
+        params.setNumItems(2)
+                .setItemsFocusable(true)
+                .setItemScreenSizeFactor(0.2)
+                .setMustFillScreen(false);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        if (position == 0) {
+            return ListItemFactory.button(
+                    position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+        } else {
+            return super.createView(position, parent, desiredHeight);
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesClose.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesClose.java
new file mode 100644
index 0000000..e20f633
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesClose.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+import com.android.frameworktest.util.ListItemFactory;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Each list item has two focusables that are close enough together that
+ * it shouldn't require panning to move focus.
+ */
+public class ListItemFocusablesClose extends ListScenario {
+
+
+    /**
+     * Get the child of a list item.
+     * @param listIndex The index of the currently visible items
+     * @param index The index of the child.
+     */
+    public View getChildOfItem(int listIndex, int index) {
+        return ((ViewGroup) getListView().getChildAt(listIndex)).getChildAt(index);
+
+    }
+        
+    @Override
+    protected void init(Params params) {
+        params.setItemsFocusable(true)
+                .setNumItems(2)
+                .setItemScreenSizeFactor(0.55);
+    }
+
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        return ListItemFactory.twoButtonsSeparatedByFiller(
+                position, parent.getContext(), desiredHeight);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesFarApart.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesFarApart.java
new file mode 100644
index 0000000..e974478
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesFarApart.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.frameworktest.util.ListItemFactory;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list where each item is tall with buttons that are farther apart than the screen
+ * size.  We don't want to jump over content off screen to the next button, we need to
+ * pan across the intermediate part.
+ */
+public class ListItemFocusablesFarApart extends ListScenario  {
+
+
+    @Override
+    protected void init(Params params) {
+        params.setItemsFocusable(true)
+                .setNumItems(2)
+                .setItemScreenSizeFactor(2);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        return ListItemFactory.twoButtonsSeparatedByFiller(
+                position, parent.getContext(), desiredHeight);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemISVAndButton.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemISVAndButton.java
new file mode 100644
index 0000000..d6c11b7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemISVAndButton.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.frameworktest.util.InternalSelectionView;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Each item is an internal selection view, a button, and some filler
+ */
+public class ListItemISVAndButton extends ListScenario {
+
+
+    @Override
+    protected void init(Params params) {
+        params.setItemScreenSizeFactor(2.0)
+                .setNumItems(3)
+                .setItemsFocusable(true);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        Context context = parent.getContext();
+
+        final LinearLayout ll = new LinearLayout(context);
+        ll.setOrientation(LinearLayout.VERTICAL);
+
+        final InternalSelectionView isv = new InternalSelectionView(context, 8, "ISV postion " + position);
+        isv.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                desiredHeight - 240));
+        ll.addView(isv);
+
+        final LinearLayout.LayoutParams buttonLp =
+                new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.FILL_PARENT,
+                        40);
+        final Button topButton = new Button(context);
+        topButton.setLayoutParams(
+                buttonLp);
+        topButton.setText("button " + position + ")");
+        ll.addView(topButton);
+
+        final TextView filler = new TextView(context);
+        filler.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                200));
+        filler.setText("filler");
+        ll.addView(filler);
+
+
+        return ll;
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemsExpandOnSelection.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemsExpandOnSelection.java
new file mode 100644
index 0000000..a137116
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemsExpandOnSelection.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.TextView;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list where each item expands by 1.5 when selected.
+ */
+public class ListItemsExpandOnSelection extends ListScenario {
+
+
+    @Override
+    protected void init(Params params) {
+        params.setNumItems(10)
+                .setItemScreenSizeFactor(1.0/5);
+    }
+
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        TextView result = new ExpandWhenSelectedView(parent.getContext(), desiredHeight);
+        result.setHeight(desiredHeight);
+        result.setFocusable(mItemsFocusable);
+        result.setText(getValueAtPosition(position));
+        final AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        result.setLayoutParams(lp);
+        return result;
+    }
+
+    
+    @Override
+    public View convertView(int position, View convertView, ViewGroup parent) {
+        ((ExpandWhenSelectedView)convertView).setText(getValueAtPosition(position));
+        return convertView;
+    }
+
+
+    static private class ExpandWhenSelectedView extends TextView {
+
+        private final int mDesiredHeight;
+
+        public ExpandWhenSelectedView(Context context, int desiredHeight) {
+            super(context);
+            mDesiredHeight = desiredHeight;
+        }
+
+        @Override
+        public void setSelected(boolean selected) {
+            super.setSelected(selected);
+            if (selected) {
+                setHeight((int) (mDesiredHeight * 1.5));
+            } else {
+                setHeight(mDesiredHeight);
+            }
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListLastItemPartiallyVisible.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListLastItemPartiallyVisible.java
new file mode 100644
index 0000000..23b76a9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListLastItemPartiallyVisible.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list where the very last item is partially visible, but still requires scrolling
+ * to bring it into view.
+ */
+public class ListLastItemPartiallyVisible extends ListScenario {
+
+    protected void init(Params params) {
+        params.setNumItems(5)
+                .setItemScreenSizeFactor(0.22);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListManagedCursor.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListManagedCursor.java
new file mode 100644
index 0000000..0cc242f
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListManagedCursor.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.provider.Contacts.People;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListAdapter;
+import android.widget.SimpleCursorAdapter;
+import android.widget.AdapterView.OnItemClickListener;
+
+
+public class ListManagedCursor extends ListActivity implements OnItemClickListener {
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Get a cursor with all people
+        Cursor c = getContentResolver().query(Settings.System.CONTENT_URI, null, null, null, null);
+        startManagingCursor(c);
+
+        ListAdapter adapter = new SimpleCursorAdapter(this, 
+                // Use a template that displays a text view
+                android.R.layout.simple_list_item_1, 
+                // Give the cursor to the list adatper
+                c, 
+                // Map the NAME column in the people database to...
+                new String[] {People.NAME} ,
+                // The "text1" view defined in the XML template
+                new int[] {android.R.id.text1}); 
+        setListAdapter(adapter);
+        getListView().setOnItemClickListener(this);
+    }
+    
+    public void onItemClick(AdapterView parent, View view, int position, long id) {
+        Intent dummyIntent = new Intent(this, ListSimple.class);
+        startActivity(dummyIntent);
+    }
+}
+             
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsShorterThanScreen.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsShorterThanScreen.java
new file mode 100644
index 0000000..475ab31
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsShorterThanScreen.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListOfItemsShorterThanScreen extends ListScenario {
+
+    protected void init(Params params) {
+        params.setNumItems(5)
+            .setItemScreenSizeFactor(1.1 / 4)
+            .setItemsFocusable(false);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsTallerThanScreen.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsTallerThanScreen.java
new file mode 100644
index 0000000..0d70abf
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsTallerThanScreen.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListOfItemsTallerThanScreen extends ListScenario {
+
+
+    protected void init(Params params) {
+        params.setNumItems(3)
+            .setItemScreenSizeFactor(4.0 / 3)
+            .setItemsFocusable(false);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortShortTallShortShort.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortShortTallShortShort.java
new file mode 100644
index 0000000..62c5aa7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortShortTallShortShort.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Exposes fading in and out multiple items.
+ */
+public class ListOfShortShortTallShortShort extends ListScenario {
+
+
+    protected void init(Params params) {
+        params.setNumItems(5)
+                .setItemScreenSizeFactor(0.1)
+                .setFadingEdgeScreenSizeFactor(0.22)
+                .setPositionScreenSizeFactorOverride(2, 1.1);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortTallShort.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortTallShort.java
new file mode 100644
index 0000000..e60dee7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortTallShort.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Two short items separated by one that is taller than the screen.
+ */
+public class ListOfShortTallShort extends ListScenario {
+
+
+    protected void init(Params params) {
+        params.setItemScreenSizeFactor(1.0 / 8)
+                .setNumItems(3)
+                .setPositionScreenSizeFactorOverride(1, 1.2);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfThinItems.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfThinItems.java
new file mode 100644
index 0000000..d613c9b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfThinItems.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListOfThinItems extends ListScenario {
+
+    protected void init(Params params) {
+
+        final int numItemsOnScreen = getScreenHeight() / 18;
+
+        params.setNumItems(numItemsOnScreen + 5)
+            .setItemScreenSizeFactor(18.0 / getScreenHeight())
+            .setItemsFocusable(false);
+    }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfTouchables.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfTouchables.java
new file mode 100644
index 0000000..0e09190
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfTouchables.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Each list item has two focusables that are close enough together that
+ * it shouldn't require panning to move focus.
+ */
+public class ListOfTouchables extends ListScenario {
+
+
+    @Override
+    protected void init(Params params) {
+        params.setItemsFocusable(true)
+                .setItemScreenSizeFactor(0.2)
+                .setNumItems(100);
+    }
+
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        Button b = new Button(this);
+        b.setText("Position " + position);
+        b.setId(position);
+        return b;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListRecyclerProfiling.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListRecyclerProfiling.java
new file mode 100644
index 0000000..3df3b9a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListRecyclerProfiling.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.ImageButton;
+import android.view.ViewDebug;
+import android.view.View;
+
+import com.android.frameworktest.R;
+
+public class ListRecyclerProfiling extends Activity {
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_recycler_profiling);
+
+        String values[] = new String[1000];
+        for (int i = 0; i < 1000; i++) {
+            values[i] = ((Integer) i).toString();
+        }
+
+        ListView listView = (ListView) findViewById(R.id.list);
+
+        ViewDebug.startRecyclerTracing("SimpleList", listView);
+
+        listView.setAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+
+        ImageButton stopProfiling = (ImageButton) findViewById(R.id.pause);
+        stopProfiling.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                ViewDebug.stopRecyclerTracing();
+            }
+        });
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListScrollListener.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListScrollListener.java
new file mode 100644
index 0000000..f5e4faf
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListScrollListener.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises change notification in a list
+ */
+public class ListScrollListener extends ListActivity implements AbsListView.OnScrollListener {
+    Handler mHandler = new Handler();
+    TextView mText;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_scroll_listener);
+
+        String values[] = new String[1000];
+        int i=0;
+        for(i=0; i<1000; i++) {
+            values[i] = ((Integer)i).toString();
+        }
+        
+        mText = (TextView) findViewById(R.id.text);
+        setListAdapter(new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, values));
+
+
+        getListView().setOnScrollListener(this);
+    }
+
+    public void onItemSelected(AdapterView parent, View v, int position, long id) {
+        mText.setText("Position " + position);
+    }
+
+    public void onNothingSelected(AdapterView parent) {
+        mText.setText("Nothing");
+    }
+
+    public void onScroll(AbsListView view, int firstCell, int cellCount, int itemCount) {
+        int last = firstCell + cellCount - 1;
+        mText.setText("Showing " + firstCell + "-" + last + "/" + itemCount);
+    }
+
+    public void onScrollStateChanged(AbsListView view, int scrollState) {        
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSetSelection.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSetSelection.java
new file mode 100644
index 0000000..87888ca
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSetSelection.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+import android.view.KeyEvent;
+import android.view.View;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+
+/**
+ * List of 1,000 items used to test calls to setSelection() in touch mode.
+ * Pressing the S key will call setSelection(0) on the list.
+ */
+public class ListSetSelection extends ListScenario {
+    private Button mButton;
+
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setNumItems(1000)
+                .setItemScreenSizeFactor(0.22);
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mButton = new Button(this);
+        mButton.setText("setSelection(0)");
+        mButton.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                getListView().setSelection(0);
+            }
+        });
+
+        getListViewContainer().addView(mButton, new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.FILL_PARENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT
+        ));
+    }
+
+    public Button getButton() {
+        return mButton;
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (event.getKeyCode() == KeyEvent.KEYCODE_S) {
+            getListView().setSelection(0);
+            return true;
+        }
+
+        return super.dispatchKeyEvent(event);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSimple.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSimple.java
new file mode 100644
index 0000000..e7517d6
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSimple.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ListSimple extends ListScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setNumItems(1000)
+                .setItemScreenSizeFactor(0.14);
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+    
+        getListView().setVerticalScrollBarEnabled(true);
+        getListView().setFadingEdgeLength(12);
+        getListView().setVerticalFadingEdgeEnabled(true);
+    }
+
+    @Override
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        View view = super.createView(position, parent, desiredHeight);
+        view.setBackgroundColor(0xFF191919);
+        ((TextView) view).setTextSize(16.0f);
+        return view;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTakeFocusFromSide.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTakeFocusFromSide.java
new file mode 100644
index 0000000..e576ea2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTakeFocusFromSide.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * Exercises moving focus into the list from the side
+ */
+public class ListTakeFocusFromSide extends ListActivity {
+
+    
+    private class ThrashListAdapter extends BaseAdapter {
+        private LayoutInflater mInflater;
+
+        private String[] mTitles = new String[100];
+
+        public ThrashListAdapter(Context context) {
+            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            mTitles = new String[100];
+
+            int i;
+            for (i = 0; i < 100; i++) {
+                mTitles[i] = "[" + i + "]";
+            }
+        }
+
+        public int getCount() {
+            return mTitles.length;
+        }
+
+        public Object getItem(int position) {
+            return position;
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TextView view;
+
+            if (convertView == null) {
+                view = (TextView) mInflater.inflate(android.R.layout.simple_list_item_1, null);
+            } else {
+                view = (TextView) convertView;
+            }
+            view.setText(mTitles[position]);
+            return view;
+        }
+
+    }
+  
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_take_focus_from_side);
+        setListAdapter(new ThrashListAdapter(this));
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListThrasher.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListThrasher.java
new file mode 100644
index 0000000..e0b18a2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListThrasher.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.Random;
+
+/**
+ * Exercises change notification in a list
+ */
+public class ListThrasher extends ListActivity implements AdapterView.OnItemSelectedListener {
+    Handler mHandler = new Handler();
+    ThrashListAdapter mAdapter;
+    Random mRandomizer = new Random();
+    TextView mText;
+
+    Runnable mThrash = new Runnable() {
+        public void run() {
+            mAdapter.bumpVersion();
+            mHandler.postDelayed(mThrash, 500);
+        }
+    };
+
+    private class ThrashListAdapter extends BaseAdapter {
+        private LayoutInflater mInflater;
+
+        /**
+         * Our data, part 1.
+         */
+        private String[] mTitles = new String[100];
+
+        /**
+         * Our data, part 2.
+         */
+        private int[] mVersion = new int[100];
+
+        public ThrashListAdapter(Context context) {
+            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            mTitles = new String[100];
+            mVersion = new int[100];
+
+            int i;
+            for (i = 0; i < 100; i++) {
+                mTitles[i] = "[" + i + "]";
+                mVersion[i] = 0;
+            }
+        }
+
+        public int getCount() {
+            return mTitles.length;
+        }
+
+        public Object getItem(int position) {
+            return position;
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TextView view;
+
+            if (convertView == null) {
+                view = (TextView) mInflater.inflate(android.R.layout.simple_list_item_1, null);
+            } else {
+                view = (TextView) convertView;
+            }
+            view.setText(mTitles[position] + " " + mVersion[position]);
+            return view;
+        }
+
+
+        public void bumpVersion() {
+            int position = mRandomizer.nextInt(getCount());
+            mVersion[position]++;
+            notifyDataSetChanged();
+        }
+
+
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.list_thrasher);
+
+        mText = (TextView) findViewById(R.id.text);
+        mAdapter = new ThrashListAdapter(this);
+        setListAdapter(mAdapter);
+
+        mHandler.postDelayed(mThrash, 5000);
+
+        getListView().setOnItemSelectedListener(this);
+    }
+
+    public void onItemSelected(AdapterView parent, View v, int position, long id) {
+        mText.setText("Position " + position);
+    }
+
+    public void onNothingSelected(AdapterView parent) {
+        mText.setText("Nothing");
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravity.java
new file mode 100644
index 0000000..6eb65a9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.view.Gravity;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic top gravity scenario, nothing fancy. Items do not
+ * fill the screen
+ */
+public class ListTopGravity extends ListScenario {
+
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setMustFillScreen(false)
+                .setNumItems(2)
+                .setItemScreenSizeFactor(0.22);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravityMany.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravityMany.java
new file mode 100644
index 0000000..8cff8ca
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravityMany.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic top gravity scenario, nothing fancy. There are
+ * more items than fit on the screen
+ */
+public class ListTopGravityMany extends ListScenario {
+    
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setNumItems(10)
+                .setItemScreenSizeFactor(0.22);
+    }    
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListViewHeight.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListViewHeight.java
new file mode 100644
index 0000000..17222d9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListViewHeight.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+
+public class ListViewHeight extends Activity {
+
+    private View mButton1;
+    private View mButton2;
+    private View mButton3;
+    
+    private View mOuterLayout;
+    private ListView mInnerList;
+
+    ArrayAdapter<String> mAdapter;
+    private String[] mStrings = {
+            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi" };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.linear_layout_listview_height);
+
+        mButton1 = findViewById(R.id.button1);
+        mButton2 = findViewById(R.id.button2);
+        mButton3 = findViewById(R.id.button3);
+        
+        mOuterLayout = findViewById(R.id.layout);
+        mInnerList = (ListView)findViewById(R.id.inner_list);
+        
+        mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, 
+                                            mStrings);
+
+        // Clicking this button will show the list view and set it to a fixed height
+        // If you then hide the views, there is no problem.
+        mButton1.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                // set listview to fixed height 
+                ViewGroup.MarginLayoutParams lp;
+                lp = (ViewGroup.MarginLayoutParams) mInnerList.getLayoutParams();
+                lp.height = 200;
+                mInnerList.setLayoutParams(lp);
+                // enable list adapter
+                mInnerList.setAdapter(mAdapter);
+                // and show it
+                mOuterLayout.setVisibility(View.VISIBLE);
+            }
+        });
+
+        // Clicking this button will show the list view and set it fill_parent height
+        // If you then hide the views, there is an NPE when calculating the ListView height.
+        mButton2.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                // set listview to fill screen
+                ViewGroup.MarginLayoutParams lp;
+                lp = (ViewGroup.MarginLayoutParams) mInnerList.getLayoutParams();
+                lp.height = lp.FILL_PARENT;
+                mInnerList.setLayoutParams(lp);
+                // enable list adapter
+                mInnerList.setAdapter(mAdapter);
+                // and show it
+                mOuterLayout.setVisibility(View.VISIBLE);
+            }
+        });
+
+        // Clicking this button will remove the list adapter and hide the outer enclosing view.
+        // We have to climb all the way to the top because the bug (not checking visibility)
+        // only occurs at the very outer loop of ViewRoot.performTraversals and in the case of
+        // an Activity, this means you have to crawl all the way out to the root view.
+        // In the search manager, it's sufficient to simply show/hide the outer search manager
+        // view to trigger the same bug.
+        mButton3.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mInnerList.setAdapter(null);
+                // hide listview's owner
+                // as it turns out, the owner doesn't take us high enough
+                // because our activity includes a title bar, thus another layer
+                View parent = (View) mOuterLayout.getParent();      // FrameLayout (app container)
+                View grandpa = (View) parent.getParent();           // LinearLayout (title+app)
+                View great = (View) grandpa.getParent();            // PhoneWindow.DecorView
+                great.setVisibility(View.GONE);
+            }
+        });
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithDisappearingItemBug.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithDisappearingItemBug.java
new file mode 100644
index 0000000..3a968af
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithDisappearingItemBug.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.Contacts.People;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.LayoutAnimationController;
+import android.view.animation.TranslateAnimation;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.Toast;
+
+/**
+ * See 1080989. You need some contacts for this adapter.
+ */
+public class ListWithDisappearingItemBug extends ListActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Toast.makeText(this, "Make sure you rotate screen to see bug", Toast.LENGTH_LONG).show();
+        
+        // Get a cursor with all people
+        Cursor c = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
+        startManagingCursor(c);
+
+        ListAdapter adapter = new SimpleCursorAdapter(this, 
+                // Use a template that displays a text view
+                R.layout.list_with_disappearing_item_bug_item, 
+                // Give the cursor to the list adatper
+                c, 
+                // Map the NAME column in the people database to...
+                new String[] {People.NAME} ,
+                // The "text1" view defined in the XML template
+                new int[] {R.id.text1}); 
+        setListAdapter(adapter);
+
+        AnimationSet set = new AnimationSet(true);
+
+        Animation animation = new AlphaAnimation(0.0f, 1.0f);
+        animation.setDuration(50);
+        set.addAnimation(animation);
+
+        animation = new TranslateAnimation(
+            Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f,
+            Animation.RELATIVE_TO_SELF, -1.0f,Animation.RELATIVE_TO_SELF, 0.0f
+        );
+        animation.setDuration(100);
+        set.addAnimation(animation);
+
+        LayoutAnimationController controller =
+                new LayoutAnimationController(set, 0.5f);
+        ListView listView = getListView();        
+        listView.setLayoutAnimation(controller);
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEditTextHeader.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEditTextHeader.java
new file mode 100644
index 0000000..b5cac2a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEditTextHeader.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list view with a single edit text in a header.
+ */
+public class ListWithEditTextHeader extends ListScenario {
+
+    @Override
+    protected void init(Params params) {
+        params.setHeaderViewCount(1)
+                .setHeaderFocusable(true)
+                .setItemsFocusable(true)
+                .setNumItems(6)
+                .setItemScreenSizeFactor(0.2);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEmptyView.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEmptyView.java
new file mode 100644
index 0000000..6f43551
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEmptyView.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ArrayAdapter;
+
+
+/**
+ * Tests using an empty view with a list */
+public class ListWithEmptyView extends ListActivity {
+    
+    private class CarefulAdapter<T> extends ArrayAdapter<T> {
+
+        public CarefulAdapter(Context context, int textViewResourceId) {
+            super(context, textViewResourceId);
+            // TODO Auto-generated constructor stub
+        }
+
+        @Override
+        public long getItemId(int position) {
+            if (position <  0 || position >= this.getCount()) {
+                throw new ArrayIndexOutOfBoundsException();
+            }
+            return super.getItemId(position);
+        }
+       
+        
+    }
+    
+    public static final int MENU_ADD = Menu.FIRST + 1;
+    public static final int MENU_REMOVE = Menu.FIRST + 2;
+    
+    private CarefulAdapter<String> mAdapter;
+    
+    private int mNextItem = 0;
+    
+    private View mEmptyView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mAdapter = new CarefulAdapter<String>(this,
+                android.R.layout.simple_list_item_1);
+        setContentView(R.layout.list_with_empty_view);
+        setListAdapter(mAdapter);
+        
+        mEmptyView = findViewById(R.id.empty);
+        getListView().setEmptyView(mEmptyView);
+    }
+    
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+        menu.add(0, MENU_ADD, 0, R.string.menu_add)
+                .setIcon(android.R.drawable.ic_menu_add);
+        menu.add(0, MENU_REMOVE, 0, R.string.menu_remove)
+                .setIcon(android.R.drawable.ic_menu_delete);
+        return true;
+    }
+    
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case MENU_ADD:
+                String str = "Item + " + mNextItem++;
+                mAdapter.add(str);
+                return true;
+            case MENU_REMOVE:
+                if (mAdapter.getCount() > 0) {
+                    mAdapter.remove(mAdapter.getItem(0));
+                }
+                return true;
+        }
+
+        return super.onOptionsItemSelected(item);
+    }
+
+    public View getEmptyView() {
+        return mEmptyView;
+    }
+   
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java
new file mode 100644
index 0000000..4ad72fd
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * The first item is unselectable, and takes up the whole screen.
+ */
+public class ListWithFirstScreenUnSelectable extends ListScenario {
+
+    @Override
+    protected void init(Params params) {
+        params.setItemScreenSizeFactor(1.2)
+                .setNumItems(2)
+                .setPositionsUnselectable(0);
+
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithHeaders.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithHeaders.java
new file mode 100644
index 0000000..d523094
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithHeaders.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+public class ListWithHeaders extends ListScenario {
+    @Override
+    protected void init(Params params) {
+        params.setStackFromBottom(false)
+                .setStartingSelectionPosition(-1)
+                .setNumItems(24)
+                .setItemScreenSizeFactor(0.14);
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final ListView listView = getListView();
+        listView.setItemsCanFocus(true);
+
+        for (int i = 0; i < 12; i++) {
+            Button header = new Button(this);
+            header.setText("Header View");
+            listView.addHeaderView(header);
+        }
+
+        for (int i = 0; i < 12; i++) {
+            Button footer = new Button(this);
+            footer.setText("Footer View");
+            listView.addFooterView(footer);
+        }
+
+        final ListAdapter adapter = listView.getAdapter();
+        listView.setAdapter(adapter);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithNoFadingEdge.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithNoFadingEdge.java
new file mode 100644
index 0000000..ecfc793
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithNoFadingEdge.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListWithNoFadingEdge extends ListScenario {
+
+    protected void init(Params params) {
+        params.setFadingEdgeScreenSizeFactor(0.0)
+                .setNumItems(10)
+                .setItemScreenSizeFactor(0.2);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOffScreenNextSelectable.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOffScreenNextSelectable.java
new file mode 100644
index 0000000..71525c0
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOffScreenNextSelectable.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Pressing down from position 0 requires looking past positions 1, 2 and 3 to
+ * an offscreen item to know that it is the next selectable.
+ */
+public class ListWithOffScreenNextSelectable extends ListScenario {
+
+
+    protected void init(Params params) {
+        params.setItemsFocusable(false)
+                .setNumItems(5)
+                .setItemScreenSizeFactor(0.25)
+                .setPositionUnselectable(1)
+                .setPositionUnselectable(2)
+                .setPositionUnselectable(3);
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOnItemSelectedAction.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOnItemSelectedAction.java
new file mode 100644
index 0000000..2683040
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOnItemSelectedAction.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.widget.TextView;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * The header text view echos the value of the selected item by using (indirectly)
+ * the {@link android.widget.AdapterView.OnItemSelectedListener}.
+ */
+public class ListWithOnItemSelectedAction extends ListScenario {
+    protected void init(Params params) {
+        params.setNumItems(8)
+                .setItemScreenSizeFactor(0.2)
+                .includeHeaderAboveList(true);
+
+    }
+
+    @Override
+    protected void positionSelected(int positon) {
+        if (positon != getListView().getSelectedItemPosition()) {
+            throw new IllegalStateException("something is fishy... the selected postion does not " +
+                    "match what the list reports.");
+        }
+        setHeaderValue(
+                ((TextView) getListView().getSelectedView()).getText().toString());
+
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithScreenOfNoSelectables.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithScreenOfNoSelectables.java
new file mode 100644
index 0000000..a2f3dc2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithScreenOfNoSelectables.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListWithScreenOfNoSelectables extends ListScenario {
+
+    protected void init(Params params) {
+        params.setNumItems(10)
+                .setItemScreenSizeFactor(0.2)
+                .setPositionsUnselectable(1, 2, 3, 4, 5, 6, 7, 8, 9);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithSeparators.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithSeparators.java
new file mode 100644
index 0000000..71ce4e7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithSeparators.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic separator scenario, nothing fancy.
+ */
+public class ListWithSeparators extends ListScenario {
+
+    protected void init(Params params) {
+        params.setItemsFocusable(false)
+                .setNumItems(5)
+                .setItemScreenSizeFactor(0.22)
+                .setPositionUnselectable(0)
+                .setPositionUnselectable(2);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/ListContextMenu.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/ListContextMenu.java
new file mode 100644
index 0000000..13c7552
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/ListContextMenu.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.menus;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * Exercises context menus in lists
+ */
+public class ListContextMenu extends ListActivity implements View.OnCreateContextMenuListener
+{
+    static final String TAG = "ListContextMenu";
+    
+    ThrashListAdapter mAdapter; 
+    
+    private class ThrashListAdapter extends BaseAdapter {
+        private LayoutInflater mInflater;
+        
+        private String[] mTitles = new String[100];
+
+        public ThrashListAdapter(Context context) {
+            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            mTitles = new String[100];
+            
+            int i;
+            for (i=0; i<100; i++) {
+                mTitles[i] = "[" + i + "]";
+            }
+        }
+
+        public int getCount() {
+            return mTitles.length;
+        }
+
+        public Object getItem(int position) {
+            return position;
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            TextView view;
+
+            if (convertView == null) {
+                view = (TextView) mInflater.inflate(android.R.layout.simple_list_item_1, null);
+            } else {
+                view = (TextView) convertView;
+            }
+            view.setText("List item " + mTitles[position]);
+            return view;
+        }
+
+    }
+    
+    @Override
+    public void onCreate(Bundle icicle) 
+    {
+        super.onCreate(icicle);
+        
+        mAdapter = new ThrashListAdapter(this);
+        getListView().setOnCreateContextMenuListener(this);
+        setListAdapter(mAdapter);
+    }
+    
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuItem item = menu.add(0, 0, 0, "Really long menu item name");
+        item.setTitleCondensed("Long name");
+        item.setIcon(R.drawable.black_square);
+        
+        SubMenu sm = menu.addSubMenu(0, 0, 0, "The 2nd item, a sub menu").setIcon(R.drawable.black_square_stretchable);
+        item = sm.getItem();
+        item.setTitleCondensed("Sub menu");
+        sm.add(1, 0, 0, "Subitem 1");
+        sm.add(1, 0, 0, "Subitem 2");
+        sm.add(1, 0, 0, "Subitem 3");
+        sm.setGroupCheckable(1, true, true);
+        menu.add(0, 0, 0, "Item 3");
+        menu.add(0, 0, 0, "Item 4");
+        menu.add(0, 0, 0, "Item 5");
+        menu.add(0, 0, 0, "Item 6");
+        menu.add(0, 0, 0, "Item 7");
+        menu.add(0, 0, 0, "Item 8");
+        menu.add(0, 0, 0, "Item 9");
+        sm = menu.addSubMenu(0, 0, 0, "Item 10 SM");
+        sm.add(0, 0, 0, "Subitem 1");
+        sm.add(0, 0, 0, "Subitem 2");
+        sm.add(0, 0, 0, "Subitem 3");
+        sm.add(0, 0, 0, "Subitem 4");
+        sm.add(0, 0, 0, "Subitem 5");
+        sm.add(0, 0, 0, "Subitem 6");
+        sm.add(0, 0, 0, "Subitem 7");
+        sm.add(0, 0, 0, "Subitem 8");
+        
+        return true;
+    }
+
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+        
+        AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
+        
+        String text = ((TextView) info.targetView).getText().toString();
+        if (text.contains("[0]")) {
+            menu.setHeaderTitle("This is a test of the title and the icon").setHeaderIcon(
+                    android.R.drawable.sym_def_app_icon);
+        } else if (text.contains("[1]")) {
+            menu.setHeaderTitle("This is a test of just the title");
+        } else {
+            TextView textView = new TextView(this);
+            textView.setText("This is a test of a custom View");
+            menu.setHeaderView(textView);
+        }
+        
+        menu.add(0, 0, 0, "Test 1");
+        SubMenu sm = menu.addSubMenu(0, 0, 0, "Test 1.5 SM");
+        sm.add(0, 0, 0, "CM Subitem 1");
+        sm.add(0, 0, 0, "CM Subitem 2");
+        sm.add(0, 0, 0, "CM Subitem 3");
+        menu.add(0, 0, 0, "Test 2");
+        menu.add(0, 0, 0, "Test 3");
+        menu.add(0, 0, 0, "Test 4");
+        menu.add(0, 0, 0, "Test 5");
+        menu.add(0, 0, 0, "Test 6");
+        menu.add(0, 0, 0, "Test 7");
+        menu.add(0, 0, 0, "Test 8");
+        menu.add(0, 0, 0, "Test 9");
+        menu.add(0, 0, 0, "Test 10");
+        menu.add(0, 0, 0, "Test 11");
+        menu.add(0, 0, 0, "Test 12");
+        menu.add(0, 0, 0, "Test 13");
+        menu.add(0, 0, 0, "Test 14");
+        menu.add(0, 0, 0, "Test 15");
+        menu.add(0, 0, 0, "Test 16");
+        menu.add(0, 0, 0, "Test 17");
+        menu.add(0, 0, 0, "Test 18");
+        menu.add(0, 0, 0, "Test 19");
+        menu.add(0, 0, 0, "Test 20");
+        menu.add(0, 0, 0, "Test 21");
+        menu.add(0, 0, 0, "Test 22");
+        menu.add(0, 0, 0, "Test 23");
+        menu.add(0, 0, 0, "Test 24");
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        Log.i(TAG, "Options item " + item.toString() + " selected.");
+        
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void onOptionsMenuClosed(Menu menu) {
+        Log.i(TAG, "Options menu closed");
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        Log.i(TAG, "Context item " + item.toString() + " selected.");
+        
+        return super.onContextItemSelected(item);
+    }
+
+    @Override
+    public void onContextMenuClosed(Menu menu) {
+        Log.i(TAG, "Context menu closed");
+    }
+    
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayout.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayout.java
new file mode 100644
index 0000000..6ed6433
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayout.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 2008 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.frameworktest.menus;
+
+import com.android.frameworktest.menus.MenuScenario.Params;
+
+import android.os.Bundle;
+import android.view.Menu;
+import android.widget.Button;
+
+public class MenuLayout extends MenuScenario {
+    private static final String LONG_TITLE = "Really really really really really really really really really really long title";
+    private static final String SHORT_TITLE = "Item";
+
+    private Button mButton;
+    
+    @Override
+    protected void onInitParams(Params params) {
+        super.onInitParams(params);
+        params
+            .setNumItems(2)
+            .setItemTitle(0, LONG_TITLE)
+            .setItemTitle(1, LONG_TITLE);
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+
+        /*
+         * This activity is meant to try a bunch of different menu layouts. So,
+         * we recreate the menu every time it is prepared.
+         */ 
+        menu.clear();
+        onCreateOptionsMenu(menu);
+        
+        return true;
+    }
+
+    public Button getButton() {
+        return mButton;
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mButton  = new Button(this);
+        setContentView(mButton);
+    }
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutLandscape.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutLandscape.java
new file mode 100644
index 0000000..8a98610
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutLandscape.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (C) 2008 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.frameworktest.menus;
+
+/**
+ * An activity (inherits from MenuLayout) that shows in landscape.
+ */
+public class MenuLayoutLandscape extends MenuLayout {
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutPortrait.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutPortrait.java
new file mode 100644
index 0000000..71e7e49
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutPortrait.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (C) 2008 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.frameworktest.menus;
+
+/**
+ * An activity (inherits from MenuLayout) that shows in portrait.
+ */
+public class MenuLayoutPortrait extends MenuLayout {
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuScenario.java
new file mode 100644
index 0000000..4df9b1b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuScenario.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.menus;
+
+import com.android.frameworktest.util.ListScenario;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuBuilder.MenuAdapter;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.SparseArray;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * Utility base class for creating various Menu scenarios. Configurable by the
+ * number of menu items. Used @link {@link ListScenario} as a reference.
+ */
+public class MenuScenario extends Activity implements MenuItem.OnMenuItemClickListener {
+    private Params mParams = new Params();
+    private Menu mMenu;
+    private MenuItem[] mItems;
+    private boolean[] mWasItemClicked;
+    private MenuAdapter[] mMenuAdapters = new MenuAdapter[MenuBuilder.NUM_TYPES];
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        dispatchInitParams();
+    }
+
+    private void dispatchInitParams() {
+        onInitParams(mParams);
+        onParamsChanged();
+    }
+    
+    public void setParams(Params params) {
+        mParams = params;
+        onParamsChanged();
+    }
+    
+    public void onParamsChanged() {
+        mItems = new MenuItem[mParams.numItems];
+        mWasItemClicked = new boolean[mParams.numItems];
+    }
+    
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        // Safe to hold on to
+        mMenu = menu;
+        
+        if (!mParams.shouldShowMenu) return false;
+        
+        MenuItem item;
+        for (int i = 0; i < mParams.numItems; i++) {
+            if ((item = onAddMenuItem(menu, i)) == null) {
+                // Add a default item for this position if the subclasses
+                // haven't
+                CharSequence givenTitle = mParams.itemTitles.get(i);
+                item = menu.add(0, 0, 0, (givenTitle != null) ? givenTitle : ("Item " + i));
+            }
+    
+            if (item != null) {
+                mItems[i] = item;
+                
+                if (mParams.listenForClicks) {
+                    item.setOnMenuItemClickListener(this);
+                }
+            }
+                
+        }
+        
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        // Safe to hold on to
+        mMenu = menu;
+
+        return mParams.shouldShowMenu;
+    }
+
+    /**
+     * Override this to add an item to the menu.
+     * 
+     * @param itemPosition The position of the item to add (only for your
+     *            reference).
+     * @return The item that was added to the menu, or null if nothing was
+     *         added.
+     */
+    protected MenuItem onAddMenuItem(Menu menu, int itemPosition) {
+        return null;
+    }
+    
+    /**
+     * Override this to set the parameters for the scenario. Call through to super first.
+     * 
+     * @param params
+     */
+    protected void onInitParams(Params params) {
+    }
+    
+    public Menu getMenu() {
+        return mMenu;
+    }
+    
+    public boolean onMenuItemClick(MenuItem item) {
+        final int position = findItemPosition(item);
+        if (position < 0) return false;
+        
+        mWasItemClicked[position] = true;
+        
+        return true;
+    }
+
+    public boolean wasItemClicked(int position) {
+        return mWasItemClicked[position];
+    }
+
+    /**
+     * Finds the position for a given Item.
+     * 
+     * @param item The item to find.
+     * @return The position, or -1 if not found.
+     */
+    public int findItemPosition(MenuItem item) {
+        // Could create reverse mapping, but optimizations aren't important (yet :P)
+        for (int i = 0; i < mParams.numItems; i++) {
+            if (mItems[i] == item) return i;
+        }
+        
+        return -1;
+    }
+    
+    /**
+     * @see MenuBuilder#getMenuAdapter(int)
+     */
+    public MenuAdapter getMenuAdapter(int menuType) {
+        if (mMenuAdapters[menuType] == null) {
+            mMenuAdapters[menuType] = ((MenuBuilder) mMenu).getMenuAdapter(menuType);
+        }
+        
+        return mMenuAdapters[menuType];
+    }
+
+    /**
+     * Gets a menu view. Call this after you're sure it has been shown,
+     * otherwise it may not have the proper layout_* attributes set.
+     * 
+     * @param menuType The type of menu.
+     * @return The MenuView for that type.
+     */
+    public View getMenuView(int menuType) {
+        return ((MenuBuilder) mMenu).getMenuView(menuType, null);
+    }
+    
+    /**
+     * Gets the menu item view for a given position.
+     * 
+     * @param menuType The type of menu.
+     * @param position The position of the item.
+     * @return The menu item view for the given item in the given menu type.
+     */
+    public View getItemView(int menuType, int position) {
+        return getMenuAdapter(menuType).getView(position, null, null);
+    }
+    
+    public static class Params {
+        // Using as data structure, so no m prefix
+        private boolean shouldShowMenu = true;
+        private int numItems = 10;
+        private boolean listenForClicks = true;
+        private SparseArray<CharSequence> itemTitles = new SparseArray<CharSequence>();
+
+        public Params setShouldShowMenu(boolean shouldShowMenu) {
+            this.shouldShowMenu = shouldShowMenu;
+            return this;
+        }
+        
+        public Params setNumItems(int numItems) {
+            this.numItems = numItems;
+            return this;
+        }
+        
+        public Params setListenForClicks(boolean listenForClicks) {
+            this.listenForClicks = listenForClicks;
+            return this;
+        }
+        
+        public Params setItemTitle(int itemPos, CharSequence title) {
+            itemTitles.put(itemPos, title);
+            return this;
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuWith1Item.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuWith1Item.java
new file mode 100644
index 0000000..d7468f5
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuWith1Item.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.menus;
+
+import android.os.Bundle;
+import android.widget.Button;
+
+public class MenuWith1Item extends MenuScenario {
+
+    private Button mButton;
+
+    @Override
+    protected void onInitParams(Params params) {
+        super.onInitParams(params);
+        
+        params.setNumItems(1);
+    }
+
+    public Button getButton() {
+        return mButton;
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mButton  = new Button(this);
+        setContentView(mButton);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/performance/InvalidateCycle.java b/tests/FrameworkTest/src/com/android/frameworktest/performance/InvalidateCycle.java
new file mode 100644
index 0000000..8663f06
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/performance/InvalidateCycle.java
@@ -0,0 +1,49 @@
+package com.android.frameworktest.performance;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Handler;
+import android.view.View;
+import android.view.ViewGroup;
+import android.content.Context;
+import android.graphics.Canvas;
+
+public class InvalidateCycle extends Activity {
+    private boolean mStartProfiling;
+    private InvalidateCycle.AutoInvalidateView mView;
+
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mView = new AutoInvalidateView(this);
+        mView.setLayoutParams(new ViewGroup.LayoutParams(16, 16));
+        setContentView(mView);
+
+        new Handler().postDelayed(new Runnable() {
+            public void run() {
+                mStartProfiling = true;
+                android.util.Log.d("Performance", "Profiling started");
+                Debug.startMethodTracing("invalidateCycle");
+                mView.invalidate();
+            }
+        }, 15000);
+    }
+
+    private class AutoInvalidateView extends View {
+        private boolean mFirstDraw;
+
+        public AutoInvalidateView(Context context) {
+            super(context);
+        }
+
+        protected void onDraw(Canvas canvas) {
+            if (mStartProfiling && !mFirstDraw) {
+                Debug.stopMethodTracing();
+                android.util.Log.d("Performance", "Profiling ended");
+                mFirstDraw = true;
+            }
+            canvas.drawColor(0xFFFF0000);            
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionView.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionView.java
new file mode 100644
index 0000000..986b800
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionView.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.scroll;
+
+import com.android.frameworktest.util.InternalSelectionView;
+import com.android.frameworktest.util.ScrollViewScenario;
+
+import android.widget.Button;
+
+/**
+ * A button above a tall internal selection view, wrapped in a scroll view.
+ */
+public class ButtonAboveTallInternalSelectionView extends ScrollViewScenario {
+
+    private final int mNumRowsInIsv = 5;
+
+
+    public Button getButtonAbove() {
+        return getContentChildAt(0);
+    }
+
+    public InternalSelectionView getIsv() {
+        return getContentChildAt(1);
+    }
+
+
+    protected void init(Params params) {
+        params.addButton("howdy", 0.1f)
+                .addInternalSelectionView(mNumRowsInIsv, 1.1f)
+                .addButton("below", 0.1f);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonsWithTallTextViewInBetween.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonsWithTallTextViewInBetween.java
new file mode 100644
index 0000000..ed098aa
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonsWithTallTextViewInBetween.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.scroll;
+
+import com.android.frameworktest.util.ScrollViewScenario;
+
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Two buttons sandwiching a tall text view (good for testing panning across
+ * before getting to next button).
+ */
+public class ButtonsWithTallTextViewInBetween extends ScrollViewScenario {
+
+    public Button getTopButton() {
+        return getContentChildAt(0);
+    }
+
+    public TextView getMiddleFiller() {
+        return getContentChildAt(1);
+    }
+
+    public Button getBottomButton() {
+        LinearLayout ll = getContentChildAt(2);
+        return (Button) ll.getChildAt(0);
+    }
+
+    protected void init(Params params) {
+        
+        params.addButton("top button", 0.2f)
+                .addTextView("middle filler", 1.51f)
+                .addVerticalLLOfButtons("bottom", 1, 0.2f);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisible.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisible.java
new file mode 100644
index 0000000..affd3c7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisible.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.scroll;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.Rect;
+import android.view.View;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+/**
+ * A screen with some scenarios that exercise {@link ScrollView}'s implementation
+ * of {@link android.view.ViewGroup#requestChildRectangleOnScreen}:
+ * <li>Scrolling to something off screen (from top and from bottom)
+ * <li>Scrolling to bring something that is larger than the screen on screen
+ *  (from top and from bottom).
+ */
+public class RequestRectangleVisible extends Activity {
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.scroll_to_rectangle);
+
+        final Rect rect = new Rect();
+        final View childToMakeVisible = findViewById(R.id.childToMakeVisible);
+
+        final TextView topBlob = (TextView) findViewById(R.id.topBlob);
+        final TextView bottomBlob = (TextView) findViewById(R.id.bottomBlob);
+
+        // estimate to get blobs larger than screen
+        int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
+        int numLinesForScreen = screenHeight / 18;
+
+        for (int i = 0; i < numLinesForScreen; i++) {
+            topBlob.append(i + " another line in the blob\n");
+            bottomBlob.append(i + " another line in the blob\n");
+        }
+
+        findViewById(R.id.scrollToRectFromTop).setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                rect.set(0, 0, childToMakeVisible.getLeft(), childToMakeVisible.getHeight());
+                childToMakeVisible.requestRectangleOnScreen(rect, true);
+            }
+        });
+
+        findViewById(R.id.scrollToRectFromTop2).setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                rect.set(0, 0, topBlob.getWidth(), topBlob.getHeight());
+                topBlob.requestRectangleOnScreen(rect, true);
+            }
+        });
+
+        findViewById(R.id.scrollToRectFromBottom).setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                rect.set(0, 0, childToMakeVisible.getLeft(), childToMakeVisible.getHeight());
+                childToMakeVisible.requestRectangleOnScreen(rect, true);
+            }
+        });
+
+        findViewById(R.id.scrollToRectFromBottom2).setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+                rect.set(0, 0, bottomBlob.getWidth(), bottomBlob.getHeight());
+                bottomBlob.requestRectangleOnScreen(rect, true);
+            }
+        });
+        
+    }
+
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScroll.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScroll.java
new file mode 100644
index 0000000..0a8dc30
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScroll.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.scroll;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Button;
+import android.view.View;
+import android.graphics.Rect;
+
+public class RequestRectangleVisibleWithInternalScroll extends Activity {
+
+    private int scrollYofBlob = 52;
+
+    private TextView mTextBlob;
+    private Button mScrollToBlob;
+
+
+    public int getScrollYofBlob() {
+        return scrollYofBlob;
+    }
+
+
+    public TextView getTextBlob() {
+        return mTextBlob;
+    }
+
+
+    public Button getScrollToBlob() {
+        return mScrollToBlob;
+    }
+
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.scroll_to_rect_with_internal_scroll);
+
+        mTextBlob = (TextView) findViewById(R.id.blob);
+        mTextBlob.scrollBy(0, scrollYofBlob);
+
+
+        mScrollToBlob = (Button) findViewById(R.id.scrollToBlob);
+        mScrollToBlob.setOnClickListener(new View.OnClickListener() {
+
+            public void onClick(View v) {
+
+                // the rect we want to make visible is offset to match
+                // the internal scroll
+                Rect rect = new Rect();
+                rect.set(0, 0, 0, mTextBlob.getHeight());
+                rect.offset(0, mTextBlob.getScrollY());
+                mTextBlob.requestRectangleOnScreen(rect);
+            }
+        });
+    }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabels.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabels.java
new file mode 100644
index 0000000..4763ab1
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabels.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.scroll;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Button;
+
+
+/**
+ * Basic scroll view example
+ */
+public class ScrollViewButtonsAndLabels extends Activity {
+
+    private ScrollView mScrollView;
+    private LinearLayout mLinearLayout;
+
+    private int mNumGroups = 10;
+
+
+    public ScrollView getScrollView() {
+        return mScrollView;
+    }
+
+    public LinearLayout getLinearLayout() {
+        return mLinearLayout;
+    }
+
+    public int getNumButtons() {
+        return mNumGroups;
+    }
+
+    public Button getButton(int groupNum) {
+        if (groupNum > mNumGroups) {
+            throw new IllegalArgumentException("groupNum > " + mNumGroups);
+        }
+        return (Button) mLinearLayout.getChildAt(2*groupNum);
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.scrollview_linear_layout);
+
+
+        // estimated ratio to get enough buttons so a couple are off screen
+        int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
+        mNumGroups = screenHeight / 30;
+
+        mScrollView = (ScrollView) findViewById(R.id.scrollView);
+        mLinearLayout = (LinearLayout) findViewById(R.id.layout);
+
+        LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.FILL_PARENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT
+        );
+
+        for (int i = 0; i < mNumGroups; i++) {
+            // want button to be first and last
+            if (i > 0) {
+                TextView textView = new TextView(this);
+                textView.setText("Text View " + i);
+                mLinearLayout.addView(textView, p);
+            }
+
+            Button button = new Button(this);
+            button.setText("Button " + (i + 1));
+            mLinearLayout.addView(button, p);
+        }
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/ShortButtons.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ShortButtons.java
new file mode 100644
index 0000000..b903382
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ShortButtons.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.scroll;
+
+import com.android.frameworktest.util.ScrollViewScenario;
+
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+/**
+ * A series of short buttons, some of which are embedded within another
+ * layout.
+ */
+public class ShortButtons extends ScrollViewScenario {
+
+    private final int mNumButtons = 10;
+    protected final float mButtonHeightFactor = 0.2f;
+
+    public int getNumButtons() {
+        return mNumButtons;
+    }
+
+    public Button getButtonAt(int index) {
+        if (index < 3) {
+            return getContentChildAt(index);
+        } else {
+            LinearLayout ll = getContentChildAt(3);
+            return (Button) ll.getChildAt(index - 3);
+        }
+    }
+
+    @Override
+    protected void init(Params params) {
+        final int numButtonsInSubLayout = getNumButtons() - 3;
+        params.addButtons(3, "top-level", mButtonHeightFactor)
+                .addVerticalLLOfButtons("embedded",
+                        numButtonsInSubLayout,
+                        numButtonsInSubLayout * mButtonHeightFactor);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/TallTextAboveButton.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/TallTextAboveButton.java
new file mode 100644
index 0000000..8b2e4f9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/TallTextAboveButton.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.scroll;
+
+import com.android.frameworktest.util.ScrollViewScenario;
+
+/**
+ * An (unfocusable) text view that takes up more than the height
+ * of the screen followed by a button.
+ */
+public class TallTextAboveButton extends ScrollViewScenario {
+
+    protected void init(Params params) {
+        params.addTextView("top tall", 1.1f)
+                .addButton("button", 0.2f);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java b/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java
new file mode 100644
index 0000000..b812181
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.settings;
+
+import android.os.IHardwareService;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+import com.android.frameworktest.R;
+
+/**
+ * Tries to set the brightness to 0. Should be silently thwarted by the framework.
+ */
+public class BrightnessLimit extends Activity implements OnClickListener {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        setContentView(R.layout.brightness_limit);
+        
+        Button b = (Button) findViewById(R.id.go);
+        b.setOnClickListener(this);
+    }
+
+    public void onClick(View v) {
+        IHardwareService hardware = IHardwareService.Stub.asInterface(
+                ServiceManager.getService("hardware"));
+        if (hardware != null) {
+            try {
+                hardware.setScreenBacklight(0);
+            } catch (RemoteException darn) {
+                
+            }
+        }
+        Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0);
+    }
+}
+
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/settings/RingtonePickerActivityLauncher.java b/tests/FrameworkTest/src/com/android/frameworktest/settings/RingtonePickerActivityLauncher.java
new file mode 100644
index 0000000..19113da
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/settings/RingtonePickerActivityLauncher.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.settings;
+
+import com.android.internal.app.RingtonePickerActivity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * Activity that will launch the RingtonePickerActivity as a subactivity, and
+ * waits for its result.
+ */
+public class RingtonePickerActivityLauncher extends Activity {
+
+    private static final String TAG = "RingtonePickerActivityLauncher";
+    
+    public boolean resultReceived = false;
+    
+    public int resultCode;
+    public Intent result;
+
+    public Uri pickedUri;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        setContentView(android.R.layout.simple_list_item_1);
+    }
+
+    /**
+     * Launches the {@link RingtonePickerActivity} and blocks until it returns.
+     * 
+     * @param showDefault {@link RingtonePickerActivity#EXTRA_SHOW_DEFAULT}
+     * @param existingUri {@link RingtonePickerActivity#EXTRA_EXISTING_URI}
+     * @param filterColumns {@link RingtonePickerActivity#EXTRA_RINGTONE_COLUMNS}
+     */
+    public void launchRingtonePickerActivity(boolean showDefault, Uri existingUri,
+            int types) {
+        Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
+        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, showDefault);
+        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, existingUri);
+        intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, types);
+        startActivityForResult(intent, 0);
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+       
+        resultReceived = true;
+
+        this.resultCode = resultCode;
+        this.result = data;
+        
+        if (data != null) {
+            this.pickedUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+        }
+    }
+    
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ExpandableListScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ExpandableListScenario.java
new file mode 100644
index 0000000..f72cbe8
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ExpandableListScenario.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+/**
+ * Utility base class for creating various Expandable List scenarios.
+ * <p>
+ * WARNING: A lot of the features are mixed between ListView's expected position
+ * (flat list position) and an ExpandableListView's expected position.  You must add/change
+ * features as you need them.
+ * 
+ * @see ListScenario
+ */
+public abstract class ExpandableListScenario extends ListScenario {
+    protected ExpandableListAdapter mAdapter; 
+    protected List<MyGroup> mGroups;
+    
+    @Override
+    protected ListView createListView() {
+        return new ExpandableListView(this);
+    }
+
+    @Override
+    protected Params createParams() {
+        return new ExpandableParams();
+    }
+
+    @Override
+    protected void setAdapter(ListView listView) {
+        ((ExpandableListView) listView).setAdapter(mAdapter = createAdapter());
+    }
+    
+    protected ExpandableListAdapter createAdapter() {
+        return new MyAdapter();
+    }
+    
+    @Override
+    protected void readAndValidateParams(Params params) {
+        ExpandableParams expandableParams = (ExpandableParams) params;
+        
+        int[] numChildren = expandableParams.mNumChildren;
+        
+        mGroups = new ArrayList<MyGroup>(numChildren.length);
+        for (int i = 0; i < numChildren.length; i++) {
+            mGroups.add(new MyGroup(numChildren[i]));
+        }
+        
+        expandableParams.superSetNumItems();
+        
+        super.readAndValidateParams(params);
+    }
+
+    /**
+     * Get the ExpandableListView widget.
+     * @return The main widget.
+     */
+    public ExpandableListView getExpandableListView() {
+        return (ExpandableListView) super.getListView();
+    }
+
+    public static class ExpandableParams extends Params {
+        private int[] mNumChildren;
+        
+        /**
+         * Sets the number of children per group.
+         *  
+         * @param numChildrenPerGroup The number of children per group.
+         */
+        public ExpandableParams setNumChildren(int[] numChildren) {
+            mNumChildren = numChildren;
+            return this;
+        }
+
+        /**
+         * Sets the number of items on the superclass based on the number of
+         * groups and children per group.
+         */
+        private ExpandableParams superSetNumItems() {
+            int numItems = 0;
+            
+            if (mNumChildren != null) {
+                for (int i = mNumChildren.length - 1; i >= 0; i--) {
+                    numItems += mNumChildren[i];
+                }
+            }
+            
+            super.setNumItems(numItems);
+            
+            return this;
+        }
+        
+        @Override
+        public Params setNumItems(int numItems) {
+            throw new IllegalStateException("Use setNumGroups and setNumChildren instead.");
+        }
+
+        @Override
+        public ExpandableParams setFadingEdgeScreenSizeFactor(double fadingEdgeScreenSizeFactor) {
+            return (ExpandableParams) super.setFadingEdgeScreenSizeFactor(fadingEdgeScreenSizeFactor);
+        }
+
+        @Override
+        public ExpandableParams setItemScreenSizeFactor(double itemScreenSizeFactor) {
+            return (ExpandableParams) super.setItemScreenSizeFactor(itemScreenSizeFactor);
+        }
+
+        @Override
+        public ExpandableParams setItemsFocusable(boolean itemsFocusable) {
+            return (ExpandableParams) super.setItemsFocusable(itemsFocusable);
+        }
+
+        @Override
+        public ExpandableParams setMustFillScreen(boolean fillScreen) {
+            return (ExpandableParams) super.setMustFillScreen(fillScreen);
+        }
+
+        @Override
+        public ExpandableParams setPositionScreenSizeFactorOverride(int position, double itemScreenSizeFactor) {
+            return (ExpandableParams) super.setPositionScreenSizeFactorOverride(position, itemScreenSizeFactor);
+        }
+
+        @Override
+        public ExpandableParams setPositionUnselectable(int position) {
+            return (ExpandableParams) super.setPositionUnselectable(position);
+        }
+
+        @Override
+        public ExpandableParams setStackFromBottom(boolean stackFromBottom) {
+            return (ExpandableParams) super.setStackFromBottom(stackFromBottom);
+        }
+
+        @Override
+        public ExpandableParams setStartingSelectionPosition(int startingSelectionPosition) {
+            return (ExpandableParams) super.setStartingSelectionPosition(startingSelectionPosition);
+        }
+
+        @Override
+        public ExpandableParams setConnectAdapter(boolean connectAdapter) {
+            return (ExpandableParams) super.setConnectAdapter(connectAdapter);
+        }
+    }
+
+    /**
+     * Gets a string for the value of some item.
+     * @param packedPosition The position of the item.
+     * @return The string.
+     */
+    public final String getValueAtPosition(long packedPosition) {
+        final int type = ExpandableListView.getPackedPositionType(packedPosition);
+        
+        if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
+            return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
+                    .children.get(ExpandableListView.getPackedPositionChild(packedPosition))
+                    .name;
+        } else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
+            return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
+                    .name;
+        } else {
+            throw new IllegalStateException("packedPosition is not a valid position.");
+        }
+    }
+
+    /**
+     * Whether a particular position is out of bounds.
+     * 
+     * @param packedPosition The packed position.
+     * @return Whether it's out of bounds.
+     */
+    private boolean isOutOfBounds(long packedPosition) {
+        final int type = ExpandableListView.getPackedPositionType(packedPosition);
+        
+        if (type == ExpandableListView.PACKED_POSITION_TYPE_NULL) {
+            throw new IllegalStateException("packedPosition is not a valid position.");
+        }
+
+        final int group = ExpandableListView.getPackedPositionGroup(packedPosition); 
+        if (group >= mGroups.size() || group < 0) {
+            return true;
+        }
+        
+        if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
+            final int child = ExpandableListView.getPackedPositionChild(packedPosition); 
+            if (child >= mGroups.get(group).children.size() || child < 0) {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    /**
+     * Gets a view for the packed position, possibly reusing the convertView.
+     * 
+     * @param packedPosition The position to get a view for.
+     * @param convertView Optional view to convert.
+     * @param parent The future parent.
+     * @return A view.
+     */
+    private View getView(long packedPosition, View convertView, ViewGroup parent) {
+        if (isOutOfBounds(packedPosition)) {
+            throw new IllegalStateException("position out of range for adapter!");
+        }
+        
+        final ExpandableListView elv = getExpandableListView();
+        final int flPos = elv.getFlatListPosition(packedPosition); 
+        
+        if (convertView != null) {
+            ((TextView) convertView).setText(getValueAtPosition(packedPosition));
+            convertView.setId(flPos);
+            return convertView;
+        }
+
+        int desiredHeight = getHeightForPosition(flPos);
+        return createView(packedPosition, flPos, parent, desiredHeight);
+    }
+    
+    /**
+     * Create a view for a group or child position.
+     * 
+     * @param packedPosition The packed position (has type, group pos, and optionally child pos).
+     * @param flPos The flat list position (the position that the ListView goes by).
+     * @param parent The parent view.
+     * @param desiredHeight The desired height.
+     * @return A view.
+     */
+    protected View createView(long packedPosition, int flPos, ViewGroup parent, int desiredHeight) {
+        TextView result = new TextView(parent.getContext());
+        result.setHeight(desiredHeight);
+        result.setText(getValueAtPosition(packedPosition));
+        final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        result.setLayoutParams(lp);
+        result.setGravity(Gravity.CENTER_VERTICAL);
+        result.setPadding(36, 0, 0, 0);
+        result.setId(flPos);
+        return result;
+    }
+    
+    /**
+     * Returns a group index containing either the number of children or at
+     * least one child.
+     * 
+     * @param numChildren The group must have this amount, or -1 if using
+     *            atLeastOneChild.
+     * @param atLeastOneChild The group must have at least one child, or false
+     *            if using numChildren.
+     * @return A group index with the requirements.
+     */
+    public int findGroupWithNumChildren(int numChildren, boolean atLeastOneChild) {
+        final ExpandableListAdapter adapter = mAdapter;
+        
+        for (int i = adapter.getGroupCount() - 1; i >= 0; i--) {
+            final int curNumChildren = adapter.getChildrenCount(i);
+            
+            if (numChildren == curNumChildren || atLeastOneChild && curNumChildren > 0) {
+                return i;
+            }
+        }
+        
+        return -1;
+    }
+    
+    public List<MyGroup> getGroups() {
+        return mGroups;
+    }
+    
+    public ExpandableListAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Simple expandable list adapter.
+     */
+    protected class MyAdapter extends BaseExpandableListAdapter {
+        public Object getChild(int groupPosition, int childPosition) {
+            return getValueAtPosition(ExpandableListView.getPackedPositionForChild(groupPosition,
+                    childPosition));
+        }
+
+        public long getChildId(int groupPosition, int childPosition) {
+            return mGroups.get(groupPosition).children.get(childPosition).id;
+        }
+
+        public int getChildrenCount(int groupPosition) {
+            return mGroups.get(groupPosition).children.size();
+        }
+
+        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+                View convertView, ViewGroup parent) {
+            return getView(ExpandableListView.getPackedPositionForChild(groupPosition,
+                    childPosition), convertView, parent);
+        }
+
+        public Object getGroup(int groupPosition) {
+            return getValueAtPosition(ExpandableListView.getPackedPositionForGroup(groupPosition));
+        }
+
+        public int getGroupCount() {
+            return mGroups.size();
+        }
+
+        public long getGroupId(int groupPosition) {
+            return mGroups.get(groupPosition).id;
+        }
+
+        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+                ViewGroup parent) {
+            return getView(ExpandableListView.getPackedPositionForGroup(groupPosition),
+                    convertView, parent);
+        }
+
+        public boolean isChildSelectable(int groupPosition, int childPosition) {
+            return true;
+        }
+
+        public boolean hasStableIds() {
+            return true;
+        }
+        
+    }
+
+    public static class MyGroup {
+        private static long mNextId = 1000;
+        
+        String name;
+        long id = mNextId++;
+        List<MyChild> children;
+        
+        public MyGroup(int numChildren) {
+            name = "Group " + id;
+            children = new ArrayList<MyChild>(numChildren);
+            for (int i = 0; i < numChildren; i++) {
+                children.add(new MyChild());
+            }
+        }
+    }
+    
+    public static class MyChild {
+        private static long mNextId = 2000;
+        
+        String name;
+        long id = mNextId++;
+        
+        public MyChild() {
+            name = "Child " + id;
+        }
+    }
+    
+    @Override
+    protected final void init(Params params) {
+        init((ExpandableParams) params);
+    }
+
+    /**
+     * @see ListScenario#init
+     */
+    protected abstract void init(ExpandableParams params);
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/GridScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/util/GridScenario.java
new file mode 100644
index 0000000..746cf23
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/GridScenario.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.util;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import com.google.android.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Utility base class for creating various GridView scenarios.  Configurable by the number
+ * of items, how tall each item should be (in relation to the screen height), and
+ * what item should start with selection.
+ */
+public abstract class GridScenario extends Activity {
+
+    private GridView mGridView;
+
+    private int mNumItems;
+
+    private int mStartingSelectionPosition;
+    private double mItemScreenSizeFactor;
+    private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+
+    private int mScreenHeight;
+
+    private boolean mStackFromBottom;
+
+    private int mColumnWidth;
+    
+    private int mNumColumns;
+    
+    private int mStretchMode;
+
+    private int mVerticalSpacing;
+
+    public GridView getGridView() {
+        return mGridView;
+    }
+
+    protected int getScreenHeight() {
+        return mScreenHeight;
+    }
+    
+    /**
+     * @return The initial number of items in the grid as specified by the scenario.
+     * This number may change over time.
+     */
+    protected int getInitialNumItems() {
+        return mNumItems;
+    }
+    
+    /**
+     * @return The desired height of 1 item, ignoring overrides
+     */
+    public int getDesiredItemHeight() {
+        return (int) (mScreenHeight * mItemScreenSizeFactor);
+    }
+
+    /**
+     * Better way to pass in optional params than a honkin' paramater list :)
+     */
+    public static class Params {
+        private int mNumItems = 4;
+        private int mStartingSelectionPosition = -1;
+        private double mItemScreenSizeFactor = 1 / 5;
+
+        private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+
+        private boolean mStackFromBottom = false;
+        private boolean mMustFillScreen = true;
+
+        private int mColumnWidth = 0;
+        private int mNumColumns = GridView.AUTO_FIT;
+        private int mStretchMode = GridView.STRETCH_COLUMN_WIDTH;
+        private int mVerticalSpacing = 0;
+
+        /**
+         * Set the number of items in the grid.
+         */
+        public Params setNumItems(int numItems) {
+            mNumItems = numItems;
+            return this;
+        }
+
+        /**
+         * Set the position that starts selected.
+         *
+         * @param startingSelectionPosition The selected position within the adapter's data set.
+         * Pass -1 if you do not want to force a selection.
+         * @return
+         */
+        public Params setStartingSelectionPosition(int startingSelectionPosition) {
+            mStartingSelectionPosition = startingSelectionPosition;
+            return this;
+        }
+
+        /**
+         * Set the factor that determines how tall each item is in relation to the
+         * screen height.
+         */
+        public Params setItemScreenSizeFactor(double itemScreenSizeFactor) {
+            mItemScreenSizeFactor = itemScreenSizeFactor;
+            return this;
+        }
+
+        /**
+         * Override the item screen size factor for a particular item.  Useful for
+         * creating grids with non-uniform item height.
+         * @param position The position in the grid.
+         * @param itemScreenSizeFactor The screen size factor to use for the height.
+         */
+        public Params setPositionScreenSizeFactorOverride(
+                int position, double itemScreenSizeFactor) {
+            mOverrideItemScreenSizeFactors.put(position, itemScreenSizeFactor);
+            return this;
+        }
+
+        /**
+         * Sets the stacking direction
+         * @param stackFromBottom
+         * @return
+         */
+        public Params setStackFromBottom(boolean stackFromBottom) {
+            mStackFromBottom = stackFromBottom;
+            return this;
+        }
+
+        /**
+         * Sets whether the sum of the height of the grid items must be at least the
+         * height of the grid view.
+         */
+        public Params setMustFillScreen(boolean fillScreen) {
+            mMustFillScreen = fillScreen;
+            return this;
+        }
+
+        /**
+         * Sets the individual width of each column.
+         *
+         * @param requestedWidth the width in pixels of the column
+         */
+        public Params setColumnWidth(int requestedWidth) {
+            mColumnWidth = requestedWidth;
+            return this;
+        }
+
+        /**
+         * Sets the number of columns in the grid.
+         */
+        public Params setNumColumns(int numColumns) {
+            mNumColumns = numColumns;
+            return this;
+        }
+        
+        /**
+         * Sets the stretch mode.
+         */
+        public Params setStretchMode(int stretchMode) {
+            mStretchMode = stretchMode;
+            return this;
+        }
+        
+        /**
+         * Sets the spacing between rows in the grid
+         */
+        public Params setVerticalSpacing(int verticalSpacing) {
+            mVerticalSpacing  = verticalSpacing;
+            return this;
+        }
+    }
+
+    /**
+     * How each scenario customizes its behavior.
+     * @param params
+     */
+    protected abstract void init(Params params);
+    
+    /**
+     * Override this to provide an different adapter for your scenario
+     * @return The adapter that this scenario will use
+     */
+    protected ListAdapter createAdapter() {
+        return new MyAdapter();
+    }
+
+    /**
+     * Override this if you want to know when something has been selected (perhaps
+     * more importantly, that {@link android.widget.AdapterView.OnItemSelectedListener} has
+     * been triggered).
+     */
+    @SuppressWarnings({ "UnusedDeclaration" })
+    protected void positionSelected(int positon) {
+
+    }
+
+    /**
+     * Override this if you want to know that nothing is selected.
+     */
+    protected void nothingSelected() {
+
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // turn off title bar
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+        mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+
+        final Params params = new Params();
+        init(params);
+
+        readAndValidateParams(params);
+
+        mGridView = new GridView(this);
+        mGridView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        mGridView.setDrawSelectorOnTop(false);
+        if (mNumColumns >= GridView.AUTO_FIT) {
+            mGridView.setNumColumns(mNumColumns);
+        }
+        if (mColumnWidth > 0) {
+            mGridView.setColumnWidth(mColumnWidth);
+        }
+        if (mVerticalSpacing > 0) {
+            mGridView.setVerticalSpacing(mVerticalSpacing);
+        }
+        mGridView.setStretchMode(mStretchMode);
+        mGridView.setAdapter(createAdapter());
+        if (mStartingSelectionPosition >= 0) {
+            mGridView.setSelection(mStartingSelectionPosition);
+        }
+        mGridView.setPadding(10, 10, 10, 10);
+        mGridView.setStackFromBottom(mStackFromBottom);
+
+        mGridView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            public void onItemSelected(AdapterView parent, View v, int position, long id) {
+                positionSelected(position);
+            }
+
+            public void onNothingSelected(AdapterView parent) {
+                nothingSelected();
+            }
+        });
+
+        setContentView(mGridView);
+    }
+    
+    
+
+    /**
+     * Read in and validate all of the params passed in by the scenario.
+     * @param params
+     */
+    private void readAndValidateParams(Params params) {
+        if (params.mMustFillScreen ) {
+            double totalFactor = 0.0;
+            for (int i = 0; i < params.mNumItems; i++) {
+                if (params.mOverrideItemScreenSizeFactors.containsKey(i)) {
+                    totalFactor += params.mOverrideItemScreenSizeFactors.get(i);
+                } else {
+                    totalFactor += params.mItemScreenSizeFactor;
+                }
+            }
+            if (totalFactor < 1.0) {
+                throw new IllegalArgumentException("grid items must combine to be at least " +
+                        "the height of the screen.  this is not the case with " + params.mNumItems
+                        + " items and " + params.mItemScreenSizeFactor + " screen factor and " +
+                        "screen height of " + mScreenHeight);
+            }
+        }
+
+        mNumItems = params.mNumItems;
+        mStartingSelectionPosition = params.mStartingSelectionPosition;
+        mItemScreenSizeFactor = params.mItemScreenSizeFactor;
+
+        mOverrideItemScreenSizeFactors.putAll(params.mOverrideItemScreenSizeFactors);
+
+        mStackFromBottom = params.mStackFromBottom;
+        mColumnWidth = params.mColumnWidth;
+        mNumColumns = params.mNumColumns;
+        mStretchMode = params.mStretchMode;
+        mVerticalSpacing = params.mVerticalSpacing;
+    }
+
+    public final String getValueAtPosition(int position) {
+        return "postion " + position;
+    }
+
+    /**
+     * Create a view for a grid item.  Override this to create a custom view beyond
+     * the simple focusable / unfocusable text view.
+     * @param position The position.
+     * @param parent The parent
+     * @param desiredHeight The height the view should be to respect the desired item
+     *   to screen height ratio.
+     * @return a view for the grid.
+     */
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        TextView result = new TextView(parent.getContext());
+        result.setHeight(desiredHeight);
+        result.setText(getValueAtPosition(position));
+        final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        result.setLayoutParams(lp);
+        result.setId(position);
+        result.setBackgroundColor(0x55ffffff);
+        return result;
+    }
+
+
+
+    private class MyAdapter extends BaseAdapter {
+        public int getCount() {
+            return mNumItems;
+        }
+
+        public Object getItem(int position) {
+            return getValueAtPosition(position);
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView != null) {
+                ((TextView) convertView).setText(getValueAtPosition(position));
+                convertView.setId(position);
+                return convertView;
+            }
+
+            int desiredHeight = getDesiredItemHeight();
+            if (mOverrideItemScreenSizeFactors.containsKey(position)) {
+                desiredHeight = (int) (mScreenHeight * mOverrideItemScreenSizeFactors.get(position));
+            }
+            return createView(position, parent, desiredHeight);
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/InternalSelectionView.java b/tests/FrameworkTest/src/com/android/frameworktest/util/InternalSelectionView.java
new file mode 100644
index 0000000..e500b94
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/InternalSelectionView.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.util;
+
+import com.android.frameworktest.R;
+
+import android.view.View;
+import android.view.KeyEvent;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.Color;
+import android.util.AttributeSet;
+
+
+
+/**
+ * A view that has a known number of selectable rows, and maintains a notion of which
+ * row is selected. The rows take up the
+ * entire width of the view.  The height of the view is divided evenly among
+ * the rows.
+ *
+ * Notice what this view does to be a good citizen w.r.t its internal selection:
+ * 1) calls {@link View#requestRectangleOnScreen} each time the selection changes due to
+ *    internal navigation.
+ * 2) implements {@link View#getFocusedRect} by filling in the rectangle of the currently
+ *    selected row
+ * 3) overrides {@link View#onFocusChanged} and sets selection appropriately according to
+ *    the previously focused rectangle.
+ */
+public class InternalSelectionView extends View {
+
+    private Paint mPainter = new Paint();
+    private Paint mTextPaint = new Paint();
+    private Rect mTempRect = new Rect();
+
+    private int mNumRows = 5;
+    private int mSelectedRow = 0;
+    private final int mEstimatedPixelHeight = 10;
+
+    private Integer mDesiredHeight = null;
+    private String mLabel = null;
+
+    public InternalSelectionView(Context context, int numRows, String label) {
+        super(context);
+        mNumRows = numRows;
+        mLabel = label;
+        init();
+    }
+
+    public InternalSelectionView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        TypedArray a =
+                context.obtainStyledAttributes(
+                        attrs, R.styleable.SelectableRowView);
+        mNumRows = a.getInt(R.styleable.SelectableRowView_numRows, 5);
+        init();
+    }
+
+    private void init() {
+        setFocusable(true);
+        mTextPaint.setAntiAlias(true);
+        mTextPaint.setTextSize(10);
+        mTextPaint.setColor(Color.WHITE);
+    }
+
+    public int getNumRows() {
+        return mNumRows;
+    }
+
+    public int getSelectedRow() {
+        return mSelectedRow;
+    }
+
+    public void setDesiredHeight(int desiredHeight) {
+        mDesiredHeight = desiredHeight;
+    }
+
+    public String getLabel() {
+        return mLabel;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        setMeasuredDimension(
+            measureWidth(widthMeasureSpec),
+            measureHeight(heightMeasureSpec));
+    }
+
+    private int measureWidth(int measureSpec) {
+        int specMode = MeasureSpec.getMode(measureSpec);
+        int specSize = MeasureSpec.getSize(measureSpec);
+
+        int desiredWidth = 300 + mPaddingLeft + mPaddingRight;
+        if (specMode == MeasureSpec.EXACTLY) {
+            // We were told how big to be
+            return specSize;
+        } else if (specMode == MeasureSpec.AT_MOST) {
+            return desiredWidth < specSize ? desiredWidth : specSize;
+        } else {
+            return desiredWidth;
+        }
+    }
+
+    private int measureHeight(int measureSpec) {
+        int specMode = MeasureSpec.getMode(measureSpec);
+        int specSize = MeasureSpec.getSize(measureSpec);
+
+        int desiredHeight = mDesiredHeight != null ?
+                mDesiredHeight :
+                mNumRows * mEstimatedPixelHeight + mPaddingTop + mPaddingBottom;
+        if (specMode == MeasureSpec.EXACTLY) {
+            // We were told how big to be
+            return specSize;
+        } else if (specMode == MeasureSpec.AT_MOST) {
+            return desiredHeight < specSize ? desiredHeight : specSize;
+        } else {
+            return desiredHeight;
+        }
+    }
+
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+
+        int rowHeight = getRowHeight();
+
+        int rectTop = mPaddingTop;
+        int rectLeft = mPaddingLeft;
+        int rectRight = getWidth() - mPaddingRight;
+        for (int i = 0; i < mNumRows; i++) {
+
+            mPainter.setColor(Color.BLACK);
+            mPainter.setAlpha(0x20);
+
+            // draw background rect
+            mTempRect.set(rectLeft, rectTop, rectRight, rectTop + rowHeight);
+            canvas.drawRect(mTempRect, mPainter);
+
+            // draw forground rect
+            if (i == mSelectedRow && hasFocus()) {
+                mPainter.setColor(Color.RED);
+                mPainter.setAlpha(0xF0);
+                mTextPaint.setAlpha(0xFF);
+            } else {
+                mPainter.setColor(Color.BLACK);
+                mPainter.setAlpha(0x40);
+                mTextPaint.setAlpha(0xF0);
+            }
+            mTempRect.set(rectLeft + 2, rectTop + 2,
+                    rectRight - 2, rectTop + rowHeight - 2);
+            canvas.drawRect(mTempRect, mPainter);
+
+            // draw text to help when visually inspecting
+            canvas.drawText(
+                    Integer.toString(i),
+                    rectLeft + 2,
+                    rectTop + 2 - (int) mTextPaint.ascent(),
+                    mTextPaint);
+
+            rectTop += rowHeight;
+        }
+    }
+
+    private int getRowHeight() {
+        return (getHeight() - mPaddingTop - mPaddingBottom) / mNumRows;
+    }
+
+    public void getRectForRow(Rect rect, int row) {
+        final int rowHeight = getRowHeight();
+        final int top = mPaddingTop + row * rowHeight;
+        rect.set(mPaddingLeft,
+                top,
+                getWidth() - mPaddingRight,
+                top + rowHeight);
+    }
+
+
+    void ensureRectVisible() {
+        getRectForRow(mTempRect, mSelectedRow);
+        requestRectangleOnScreen(mTempRect);
+    }
+
+
+    /* (non-Javadoc)
+    * @see android.view.KeyEvent.Callback#onKeyDown(int, android.view.KeyEvent)
+    */
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        switch(event.getKeyCode()) {
+            case KeyEvent.KEYCODE_DPAD_UP:
+                if (mSelectedRow > 0) {
+                    mSelectedRow--;
+                    invalidate();
+                    ensureRectVisible();
+                    return true;
+                }
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                if (mSelectedRow < (mNumRows - 1)) {
+                    mSelectedRow++;
+                    invalidate();
+                    ensureRectVisible();
+                    return true;
+                }
+                break;
+        }
+        return false;
+    }
+
+
+    @Override
+    public void getFocusedRect(Rect r) {
+        getRectForRow(r, mSelectedRow);
+    }
+
+    @Override
+    protected void onFocusChanged(boolean focused, int direction,
+            Rect previouslyFocusedRect) {
+        super.onFocusChanged(focused, direction, previouslyFocusedRect);
+
+        if (focused) {
+            switch (direction) {
+                case View.FOCUS_DOWN:
+                    mSelectedRow = 0;
+                    break;
+                case View.FOCUS_UP:
+                    mSelectedRow = mNumRows - 1;
+                    break;
+                case View.FOCUS_LEFT:  // fall through
+                case View.FOCUS_RIGHT:
+                    // set the row that is closest to the rect
+                    if (previouslyFocusedRect != null) {
+                        int y = previouslyFocusedRect.top
+                                + (previouslyFocusedRect.height() / 2);
+                        int yPerRow = getHeight() / mNumRows;
+                        mSelectedRow = y / yPerRow;
+                    } else {
+                        mSelectedRow = 0;
+                    }
+                    break;
+                default:
+                    // can't gleam any useful information about what internal
+                    // selection should be...
+                    return;
+            }
+            invalidate();
+        }
+    }
+
+    @Override
+    public String toString() {
+        if (mLabel != null) {
+            return mLabel;
+        }
+        return super.toString();
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/KeyUtils.java b/tests/FrameworkTest/src/com/android/frameworktest/util/KeyUtils.java
new file mode 100644
index 0000000..06feab4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/KeyUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.util;
+
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.InstrumentationTestCase;
+import android.view.Gravity;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+/**
+ * Reusable methods for generating key events.
+ * <p>
+ * Definitions:
+ * <li> Tap refers to pushing and releasing a button (down and up event).
+ * <li> Chord refers to pushing a modifier key, tapping a regular key, and
+ * releasing the modifier key.
+ */
+public class KeyUtils {
+    /**
+     * Simulates tapping the menu key.
+     * 
+     * @param test The test case that is being run.
+     */
+    public static void tapMenuKey(ActivityInstrumentationTestCase test) {
+        final Instrumentation inst = test.getInstrumentation();
+
+        inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
+        inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU));
+    }
+
+    /**
+     * Simulates chording the menu key.
+     * 
+     * @param test The test case that is being run.
+     * @param shortcutKey The shortcut key to tap while chording the menu key.
+     */
+    public static void chordMenuKey(ActivityInstrumentationTestCase test, char shortcutKey) {
+        final Instrumentation inst = test.getInstrumentation();
+
+        final KeyEvent pushMenuKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
+        final KeyCharacterMap keyCharMap = KeyCharacterMap.load(pushMenuKey.getDeviceId());
+        final KeyEvent shortcutKeyEvent = keyCharMap.getEvents(new char[] { shortcutKey })[0];
+        final int shortcutKeyCode = shortcutKeyEvent.getKeyCode();
+        
+        inst.sendKeySync(pushMenuKey);
+        inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, shortcutKeyCode));
+        inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, shortcutKeyCode));
+        inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU));
+    }
+
+    /**
+     * Simulates a long click via the keyboard.
+     * 
+     * @param test The test case that is being run. 
+     */
+    public static void longClick(ActivityInstrumentationTestCase test) {
+        final Instrumentation inst = test.getInstrumentation();
+
+        inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER));
+        try {
+            Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f));
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER));
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ListItemFactory.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ListItemFactory.java
new file mode 100644
index 0000000..4327a8a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ListItemFactory.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.util;
+
+import android.content.Context;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Reusable methods for creating more complex list items.
+ */
+public class ListItemFactory {
+
+    /**
+     * Create a view with a button at the top and bottom, with filler in between.
+     * The filler is sized to take up any space left over within desiredHeight.
+     *
+     * @param position      The position within the list.
+     * @param context       The context.
+     * @param desiredHeight The desired height of the entire view.
+     * @return The created view.
+     */
+    public static View twoButtonsSeparatedByFiller(int position, Context context, int desiredHeight) {
+        if (desiredHeight < 90) {
+            throw new IllegalArgumentException("need at least 90 pixels of height " +
+                    "to create the two buttons and leave 10 pixels for the filler");
+        }
+
+        final LinearLayout ll = new LinearLayout(context);
+        ll.setOrientation(LinearLayout.VERTICAL);
+
+        final LinearLayout.LayoutParams buttonLp =
+                new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.FILL_PARENT,
+                        50);
+
+        final Button topButton = new Button(context);
+        topButton.setLayoutParams(
+                buttonLp);
+        topButton.setText("top (position " + position + ")");
+        ll.addView(topButton);
+
+        final TextView middleFiller = new TextView(context);
+        middleFiller.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                desiredHeight - 100));
+        middleFiller.setText("filler");
+        ll.addView(middleFiller);
+
+        final Button bottomButton = new Button(context);
+        bottomButton.setLayoutParams(buttonLp);
+        bottomButton.setText("bottom (position " + position + ")");
+        ll.addView(bottomButton);
+        ll.setTag("twoButtons");
+        return ll;
+    }
+
+    public enum Slot {
+        Left,
+        Middle,
+        Right
+    }
+
+    /**
+     * Create a horizontal linear layout divided into thirds (with some margins
+     * separating the thirds), filled with buttons into some slots.
+     * @param context The context.
+     * @param desiredHeight The height of the LL.
+     * @param slots Which slots to fill with buttons.
+     * @return The linear layout.
+     */
+    public static View horizontalButtonSlots(Context context, int desiredHeight, Slot... slots) {
+
+        final LinearLayout ll = new LinearLayout(context);
+        ll.setOrientation(LinearLayout.HORIZONTAL);
+
+        final LinearLayout.LayoutParams lp
+                = new LinearLayout.LayoutParams(0, desiredHeight);
+        lp.setMargins(10, 0, 10, 0);
+        lp.weight = 0.33f;
+
+        boolean left = false;
+        boolean middle = false;
+        boolean right = false;
+        for (Slot slot : slots) {
+            switch (slot) {
+                case Left:
+                    left = true;
+                    break;
+                case Middle:
+                    middle = true;
+                    break;
+                case Right:
+                    right = true;
+                    break;
+            }
+        }
+
+        if (left) {
+            final Button button = new Button(context);
+            button.setText("left");
+            ll.addView(button, lp);
+        } else {
+           ll.addView(new View(context), lp);
+        }
+
+        if (middle) {
+            final Button button = new Button(context);
+            button.setText("center");
+            ll.addView(button, lp);
+        } else {
+           ll.addView(new View(context), lp);
+        }
+
+        if (right) {
+            final Button button = new Button(context);
+            button.setText("right");
+            ll.addView(button, lp);
+        } else {
+           ll.addView(new View(context), lp);
+        }
+
+        return ll;
+    }
+
+
+    /**
+     * Create a button ready to be a list item.
+     *
+     * @param position      The position within the list.
+     * @param context       The context.
+     * @param text          The text of the button
+     * @param desiredHeight The desired height of the button
+     * @return The created view.
+     */
+    public static View button(int position, Context context, String text, int desiredHeight) {
+        TextView result = new Button(context);
+        result.setHeight(desiredHeight);
+        result.setText(text);
+        final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        result.setLayoutParams(lp);
+        result.setId(position);
+        result.setTag("button");
+        return result;
+    }
+    
+    /**
+     * Convert an existing button view to display the data at a new position.
+     * 
+     * @param convertView Non-null Button created by {@link #button}
+     * @param text The text of the button
+     * @param position The position withion the list
+     * @return The converted view
+     */
+    public static View convertButton(View convertView, String text, int position) {
+        if (((String) convertView.getTag()).equals("button")) {
+            ((Button) convertView).setText(text);
+            convertView.setId(position);
+            return convertView;
+        } else {
+            return null;
+        }
+    }
+    
+    /**
+     * Create a text view ready to be a list item.
+     *
+     * @param position      The position within the list.
+     * @param context       The context.
+     * @param text          The text to display
+     * @param desiredHeight The desired height of the text view
+     * @return The created view.
+     */
+    public static View text(int position, Context context, String text, int desiredHeight) {
+        TextView result = new TextView(context);
+        result.setHeight(desiredHeight);
+        result.setText(text);
+        final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        result.setLayoutParams(lp);
+        result.setId(position);
+        result.setTag("text");
+        return result;
+    }
+    
+    /**
+     * Convert an existing text view to display the data at a new position.
+     * 
+     * @param convertView Non-null TextView created by {@link #text}
+     * @param text The text to display
+     * @param position The position withion the list
+     * @return The converted view
+     */
+    public static View convertText(View convertView, String text, int position) {
+        if(convertView.getTag() != null && ((String) convertView.getTag()).equals("text")) {
+            ((TextView) convertView).setText(text);
+            convertView.setId(position);
+            return convertView;
+
+        } else {
+            return null;
+        }
+    }
+    
+    /**
+     * Create a text view ready to be a list item.
+     *
+     * @param position      The position within the list.
+     * @param context       The context.
+     * @param text          The text of the button
+     * @param desiredHeight The desired height of the button
+     * @return The created view.
+     */
+    public static View doubleText(int position, Context context, String text, int desiredHeight) {
+        final LinearLayout ll = new LinearLayout(context);
+        ll.setOrientation(LinearLayout.HORIZONTAL);
+
+        final AbsListView.LayoutParams lp =
+                new AbsListView.LayoutParams(
+                        ViewGroup.LayoutParams.FILL_PARENT,
+                        desiredHeight);
+        ll.setLayoutParams(lp);
+        ll.setId(position);
+        
+        TextView t1 = new TextView(context);
+        t1.setHeight(desiredHeight);
+        t1.setText(text);
+        t1.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
+        final ViewGroup.LayoutParams lp1 = new LinearLayout.LayoutParams(
+                0,
+                ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);
+        ll.addView(t1, lp1);
+        
+        TextView t2 = new TextView(context);
+        t2.setHeight(desiredHeight);
+        t2.setText(text);
+        t2.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL);
+        final ViewGroup.LayoutParams lp2 = new LinearLayout.LayoutParams(
+                0,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                1.0f);
+
+        ll.addView(t2, lp2);
+        ll.setTag("double");
+        return ll;
+    }
+
+    
+    /**
+     * Convert an existing button view to display the data at a new position.
+     * 
+     * @param convertView Non-null view created by {@link #doubleText}
+     * @param text The text of the button
+     * @param position The position withion the list
+     * @return The converted view
+     */
+    public static View convertDoubleText(View convertView, String text, int position) {
+        if (((String) convertView.getTag()).equals("double")) {
+            TextView t1 = (TextView) ((LinearLayout) convertView).getChildAt(0);
+            TextView t2 = (TextView) ((LinearLayout) convertView).getChildAt(1);
+            t1.setText(text);
+            t2.setText(text);
+            convertView.setId(position);
+            return convertView;
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ListScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ListScenario.java
new file mode 100644
index 0000000..5889658
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ListScenario.java
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.util;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.google.android.collect.Maps;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility base class for creating various List scenarios.  Configurable by the number
+ * of items, how tall each item should be (in relation to the screen height), and
+ * what item should start with selection.
+ */
+public abstract class ListScenario extends Activity {
+
+    private ListView mListView;
+    private TextView mHeaderTextView;
+
+    private int mNumItems;
+    protected boolean mItemsFocusable;
+
+    private int mStartingSelectionPosition;
+    private double mItemScreenSizeFactor;
+    private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+
+    private int mScreenHeight;
+
+    // whether to include a text view above the list
+    private boolean mIncludeHeader;
+
+    // separators
+    private Set<Integer> mUnselectableItems = new HashSet<Integer>();
+    
+    private boolean mStackFromBottom;
+
+    private int mClickedPosition = -1;
+    
+    private int mLongClickedPosition = -1;
+    
+    private int mConvertMisses = 0;
+    
+    private int mHeaderViewCount;
+    private boolean mHeadersFocusable;
+    
+    private int mFooterViewCount;
+    private LinearLayout mLinearLayout;
+
+    public ListView getListView() {
+        return mListView;
+    }
+
+    protected int getScreenHeight() {
+        return mScreenHeight;
+    }
+
+    /**
+     * Return whether the item at position is selectable (i.e is a separator).
+     * (external users can access this info using the adapter)
+     */
+    private boolean isItemAtPositionSelectable(int position) {
+        return !mUnselectableItems.contains(position);
+    }
+
+    /**
+     * Better way to pass in optional params than a honkin' paramater list :)
+     */
+    public static class Params {
+        private int mNumItems = 4;
+        private boolean mItemsFocusable = false;
+        private int mStartingSelectionPosition = 0;
+        private double mItemScreenSizeFactor = 1 / 5;
+        private Double mFadingEdgeScreenSizeFactor = null;
+
+        private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+
+        // separators
+        private List<Integer> mUnselectableItems = new ArrayList<Integer>(8);
+        // whether to include a text view above the list
+        private boolean mIncludeHeader = false;
+        private boolean mStackFromBottom = false;
+        public boolean mMustFillScreen = true;
+        private int mHeaderViewCount;
+        private boolean mHeaderFocusable = false;
+        private int mFooterViewCount;
+
+        private boolean mConnectAdapter = true;
+
+        /**
+         * Set the number of items in the list.
+         */
+        public Params setNumItems(int numItems) {
+            mNumItems = numItems;
+            return this;
+        }
+
+        /**
+         * Set whether the items are focusable.
+         */
+        public Params setItemsFocusable(boolean itemsFocusable) {
+            mItemsFocusable = itemsFocusable;
+            return this;
+        }
+
+        /**
+         * Set the position that starts selected.
+         *
+         * @param startingSelectionPosition The selected position within the adapter's data set.
+         * Pass -1 if you do not want to force a selection.
+         * @return
+         */
+        public Params setStartingSelectionPosition(int startingSelectionPosition) {
+            mStartingSelectionPosition = startingSelectionPosition;
+            return this;
+        }
+
+        /**
+         * Set the factor that determines how tall each item is in relation to the
+         * screen height.
+         */
+        public Params setItemScreenSizeFactor(double itemScreenSizeFactor) {
+            mItemScreenSizeFactor = itemScreenSizeFactor;
+            return this;
+        }
+
+        /**
+         * Override the item screen size factor for a particular item.  Useful for
+         * creating lists with non-uniform item height.
+         * @param position The position in the list.
+         * @param itemScreenSizeFactor The screen size factor to use for the height.
+         */
+        public Params setPositionScreenSizeFactorOverride(
+                int position, double itemScreenSizeFactor) {
+            mOverrideItemScreenSizeFactors.put(position, itemScreenSizeFactor);
+            return this;
+        }
+
+        /**
+         * Set a position as unselectable (a.k.a a separator)
+         * @param position
+         * @return
+         */
+        public Params setPositionUnselectable(int position) {
+            mUnselectableItems.add(position);
+            return this;
+        }
+
+        /**
+         * Set positions as unselectable (a.k.a a separator)
+         */
+        public Params setPositionsUnselectable(int ...positions) {
+            for (int pos : positions) {
+                setPositionUnselectable(pos);
+            }
+            return this;
+        }
+
+        /**
+         * Include a header text view above the list.
+         * @param includeHeader
+         * @return
+         */
+        public Params includeHeaderAboveList(boolean includeHeader) {
+            mIncludeHeader = includeHeader;
+            return this;
+        }
+        
+        /**
+         * Sets the stacking direction
+         * @param stackFromBottom
+         * @return
+         */
+        public Params setStackFromBottom(boolean stackFromBottom) {
+            mStackFromBottom = stackFromBottom;
+            return this;
+        }
+        
+        /**
+         * Sets whether the sum of the height of the list items must be at least the
+         * height of the list view.
+         */
+        public Params setMustFillScreen(boolean fillScreen) {
+            mMustFillScreen = fillScreen;
+            return this;
+        }
+
+        /**
+         * Set the factor for the fading edge length.
+         */
+        public Params setFadingEdgeScreenSizeFactor(double fadingEdgeScreenSizeFactor) {
+            mFadingEdgeScreenSizeFactor = fadingEdgeScreenSizeFactor;
+            return this;
+        }
+        
+        /**
+         * Set the number of header views to appear within the list
+         */
+        public Params setHeaderViewCount(int headerViewCount) {
+            mHeaderViewCount = headerViewCount;
+            return this;
+        }
+
+        /**
+         * Set whether the headers should be focusable.
+         * @param headerFocusable Whether the headers should be focusable (i.e
+         *   created as edit texts rather than text views).
+         */
+        public Params setHeaderFocusable(boolean headerFocusable) {
+            mHeaderFocusable = headerFocusable;
+            return this;
+        }
+
+        /**
+         * Set the number of footer views to appear within the list
+         */
+        public Params setFooterViewCount(int footerViewCount) {
+            mFooterViewCount = footerViewCount;
+            return this;
+        }
+        
+        /**
+         * Sets whether the {@link ListScenario} will automatically set the
+         * adapter on the list view. If this is false, the client MUST set it
+         * manually (this is useful when adding headers to the list view, which
+         * must be done before the adapter is set).
+         */
+        public Params setConnectAdapter(boolean connectAdapter) {
+            mConnectAdapter = connectAdapter;
+            return this;
+        }
+    }
+
+    /**
+     * How each scenario customizes its behavior.
+     * @param params
+     */
+    protected abstract void init(Params params);
+
+    /**
+     * Override this if you want to know when something has been selected (perhaps
+     * more importantly, that {@link android.widget.AdapterView.OnItemSelectedListener} has
+     * been triggered).
+     */
+    protected void positionSelected(int positon) {
+    }
+
+    /**
+     * Override this if you want to know that nothing is selected.
+     */
+    protected void nothingSelected() {
+    }
+    
+    /**
+     * Override this if you want to know when something has been clicked (perhaps
+     * more importantly, that {@link android.widget.AdapterView.OnItemClickListener} has
+     * been triggered).
+     */
+    protected void positionClicked(int position) {
+        setClickedPosition(position);
+    }
+    
+    /**
+     * Override this if you want to know when something has been long clicked (perhaps
+     * more importantly, that {@link android.widget.AdapterView.OnItemLongClickListener} has
+     * been triggered).
+     */
+    protected void positionLongClicked(int position) {
+        setLongClickedPosition(position);
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        // for test stability, turn off title bar
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        
+
+        mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+
+        final Params params = createParams();
+        init(params);
+
+        readAndValidateParams(params);
+
+
+        mListView = createListView();
+        mListView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        mListView.setDrawSelectorOnTop(false);
+
+        for (int i=0; i<mHeaderViewCount; i++) {
+            TextView header = mHeadersFocusable ?
+                    new EditText(this) :
+                    new TextView(this);
+            header.setText("Header: " + i);
+            mListView.addHeaderView(header);
+        }
+        
+        for (int i=0; i<mFooterViewCount; i++) {
+            TextView header = new TextView(this);
+            header.setText("Footer: " + i);
+            mListView.addFooterView(header);
+        }
+
+        if (params.mConnectAdapter) {
+            setAdapter(mListView);
+        }
+        
+        mListView.setItemsCanFocus(mItemsFocusable);
+        if (mStartingSelectionPosition >= 0) {
+            mListView.setSelection(mStartingSelectionPosition);
+        }
+        mListView.setPadding(0, 0, 0, 0);
+        mListView.setStackFromBottom(mStackFromBottom);
+        mListView.setDivider(null);
+
+        mListView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+            public void onItemSelected(AdapterView parent, View v, int position, long id) {
+                positionSelected(position);
+            }
+
+            public void onNothingSelected(AdapterView parent) {
+                nothingSelected();
+            }
+        });
+
+        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            public void onItemClick(AdapterView parent, View v, int position, long id) {
+                positionClicked(position);
+            }
+        });
+        
+        // set the fading edge length porportionally to the screen
+        // height for test stability
+        if (params.mFadingEdgeScreenSizeFactor != null) {
+            mListView.setFadingEdgeLength((int) (params.mFadingEdgeScreenSizeFactor * mScreenHeight));            
+        } else {
+            mListView.setFadingEdgeLength((int) ((64.0 / 480) * mScreenHeight));
+        }
+
+        if (mIncludeHeader) {
+            mLinearLayout = new LinearLayout(this);
+
+            mHeaderTextView = new TextView(this);
+            mHeaderTextView.setText("hi");
+            mHeaderTextView.setLayoutParams(new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT));
+            mLinearLayout.addView(mHeaderTextView);
+
+            mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+            mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT,
+                    ViewGroup.LayoutParams.FILL_PARENT));
+            mListView.setLayoutParams((new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT,
+                    0,
+                    1f)));
+
+            mLinearLayout.addView(mListView);
+            setContentView(mLinearLayout);
+        } else {
+            mLinearLayout = new LinearLayout(this);
+            mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+            mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT,
+                    ViewGroup.LayoutParams.FILL_PARENT));
+            mListView.setLayoutParams((new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT,
+                    0,
+                    1f)));
+            mLinearLayout.addView(mListView);
+            setContentView(mLinearLayout);
+        }
+    }
+
+    /**
+     * Returns the LinearLayout containing the ListView in this scenario.
+     *
+     * @return The LinearLayout in which the ListView is held.
+     */
+    protected LinearLayout getListViewContainer() {
+        return mLinearLayout;
+    }
+
+    /**
+     * Attaches a long press listener. You can find out which views were clicked by calling
+     * {@link #getLongClickedPosition()}.
+     */
+    public void enableLongPress() {
+        mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+            public boolean onItemLongClick(AdapterView parent, View v, int position, long id) {
+                positionLongClicked(position);
+                return true;
+            }
+        });
+    }
+    
+    /**
+     * @return The newly created ListView widget.
+     */
+    protected ListView createListView() {
+        return new ListView(this);
+    }
+
+    /**
+     * @return The newly created Params object.
+     */
+    protected Params createParams() {
+        return new Params();
+    }
+    
+    /**
+     * Sets an adapter on a ListView.
+     * 
+     * @param listView The ListView to set the adapter on.
+     */
+    protected void setAdapter(ListView listView) {
+        listView.setAdapter(new MyAdapter());
+    }
+    
+    /**
+     * Read in and validate all of the params passed in by the scenario.
+     * @param params
+     */
+    protected void readAndValidateParams(Params params) {
+        if (params.mMustFillScreen ) {
+            double totalFactor = 0.0;
+            for (int i = 0; i < params.mNumItems; i++) {
+                if (params.mOverrideItemScreenSizeFactors.containsKey(i)) {
+                    totalFactor += params.mOverrideItemScreenSizeFactors.get(i);
+                } else {
+                    totalFactor += params.mItemScreenSizeFactor;
+                }
+            }
+            if (totalFactor < 1.0) {
+                throw new IllegalArgumentException("list items must combine to be at least " +
+                        "the height of the screen.  this is not the case with " + params.mNumItems
+                        + " items and " + params.mItemScreenSizeFactor + " screen factor and " +
+                        "screen height of " + mScreenHeight);
+            }
+        }
+
+        mNumItems = params.mNumItems;
+        mItemsFocusable = params.mItemsFocusable;
+        mStartingSelectionPosition = params.mStartingSelectionPosition;
+        mItemScreenSizeFactor = params.mItemScreenSizeFactor;
+
+        mOverrideItemScreenSizeFactors.putAll(params.mOverrideItemScreenSizeFactors);
+
+        mUnselectableItems.addAll(params.mUnselectableItems);
+        mIncludeHeader = params.mIncludeHeader;
+        mStackFromBottom = params.mStackFromBottom;
+        mHeaderViewCount = params.mHeaderViewCount;
+        mHeadersFocusable = params.mHeaderFocusable;
+        mFooterViewCount = params.mFooterViewCount;
+    }
+
+    public final String getValueAtPosition(int position) {
+        return isItemAtPositionSelectable(position)
+                ?
+                "position " + position:
+                "------- " + position;
+    }
+
+    /**
+     * @return The height that will be set for a particular position.
+     */
+    public int getHeightForPosition(int position) {
+        int desiredHeight = (int) (mScreenHeight * mItemScreenSizeFactor);
+        if (mOverrideItemScreenSizeFactors.containsKey(position)) {
+            desiredHeight = (int) (mScreenHeight * mOverrideItemScreenSizeFactors.get(position));
+        }
+        return desiredHeight;
+    }
+
+
+    /**
+     * @return The contents of the header above the list.
+     * @throws IllegalArgumentException if there is no header.
+     */
+    public final String getHeaderValue() {
+        if (!mIncludeHeader) {
+            throw new IllegalArgumentException("no header above list");
+        }
+        return mHeaderTextView.getText().toString();
+    }
+
+    /**
+     * @param value What to put in the header text view
+     * @throws IllegalArgumentException if there is no header.
+     */
+    protected final void setHeaderValue(String value) {
+        if (!mIncludeHeader) {
+            throw new IllegalArgumentException("no header above list");
+        }
+        mHeaderTextView.setText(value);        
+    }
+
+    /**
+     * Create a view for a list item.  Override this to create a custom view beyond
+     * the simple focusable / unfocusable text view.
+     * @param position The position.
+     * @param parent The parent
+     * @param desiredHeight The height the view should be to respect the desired item
+     *   to screen height ratio.
+     * @return a view for the list.
+     */
+    protected View createView(int position, ViewGroup parent, int desiredHeight) {
+        return ListItemFactory.text(position, parent.getContext(), getValueAtPosition(position),
+                desiredHeight);
+    }
+
+    /**
+     * Convert a non-null view. 
+     */
+    public View convertView(int position, View convertView, ViewGroup parent) {
+        return ListItemFactory.convertText(convertView, getValueAtPosition(position), position);
+    }
+    
+    public void setClickedPosition(int clickedPosition) {
+        mClickedPosition = clickedPosition;
+    }
+
+    public int getClickedPosition() {
+        return mClickedPosition;
+    }
+
+    public void setLongClickedPosition(int longClickedPosition) {
+        mLongClickedPosition = longClickedPosition;
+    }
+
+    public int getLongClickedPosition() {
+        return mLongClickedPosition;
+    }
+
+    /**
+     * Have a child of the list view call {@link View#requestRectangleOnScreen(android.graphics.Rect)}.
+     * @param childIndex The index into the viewgroup children (i.e the children that are
+     *   currently visible).
+     * @param rect The rectangle, in the child's coordinates.
+     */
+    public void requestRectangleOnScreen(int childIndex, final Rect rect) {
+        final View child = getListView().getChildAt(childIndex);
+
+        child.post(new Runnable() {
+            public void run() {
+                child.requestRectangleOnScreen(rect);
+            }
+        });
+    }
+    
+    /**
+     * Return an item type for the specified position in the adapter. Override if your
+     * adapter creates more than one type.
+     */
+    public int getItemViewType(int position) {
+        return 0;
+    }
+
+    /**
+     * Return an the number of types created by the adapter. Override if your
+     * adapter creates more than one type.
+     */
+    public int getViewTypeCount() {
+        return 1;
+    }
+    
+    /**
+     * @return The number of times convertView failed
+     */
+    public int getConvertMisses() {
+        return mConvertMisses;
+    }
+
+    private class MyAdapter extends BaseAdapter {
+
+        public int getCount() {
+            return mNumItems;
+        }
+
+        public Object getItem(int position) {
+            return getValueAtPosition(position);
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return mUnselectableItems.isEmpty();
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return isItemAtPositionSelectable(position);
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            View result = null;
+            if (position >= mNumItems || position < 0) {
+                throw new IllegalStateException("position out of range for adapter!");
+            }
+
+            if (convertView != null) {
+                result = convertView(position, convertView, parent);
+                if (result == null) {
+                    mConvertMisses++;
+                }
+            }
+
+            if (result == null) {
+                int desiredHeight = getHeightForPosition(position);
+                result = createView(position, parent, desiredHeight);
+            }
+            return result;
+        }
+        
+        @Override
+        public int getItemViewType(int position) {
+            return ListScenario.this.getItemViewType(position);
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return ListScenario.this.getViewTypeCount();
+        }
+
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ListUtil.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ListUtil.java
new file mode 100644
index 0000000..1a05fac
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ListUtil.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.util;
+
+import android.app.Instrumentation;
+import android.view.KeyEvent;
+import android.widget.ListView;
+
+
+/**
+ * Various useful stuff for instrumentation testing listview.
+ */
+public class ListUtil {
+
+
+    private final ListView mListView;
+    private final Instrumentation mInstrumentation;
+
+    /**
+     * @param listView The listview to act on
+     * @param instrumentation The instrumentation to use.
+     */
+    public ListUtil(ListView listView, Instrumentation instrumentation) {
+        mListView = listView;
+        mInstrumentation = instrumentation;
+    }
+
+    /**
+     * Set the selected position of the list view.
+     * @param pos The desired position.
+     */
+    public final void setSelectedPosition(final int pos) {
+        mListView.post(new Runnable() {
+            public void run() {
+                mListView.setSelection(pos);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Get the top of the list.
+     */
+    public final int getListTop() {
+        return mListView.getListPaddingTop();
+    }
+
+    /**
+     * Get the bottom of the list.
+     */
+    public final int getListBottom() {
+        return mListView.getHeight() - mListView.getListPaddingBottom();
+    }
+
+    /**
+     * Arrow (up or down as appropriate) to the desired position in the list.
+     * @param desiredPos The desired position
+     * @throws IllegalStateException if the position can't be reached within 20 presses.
+     */
+    public final void arrowScrollToSelectedPosition(int desiredPos) {
+        if (desiredPos > mListView.getSelectedItemPosition()) {
+            arrowDownToSelectedPosition(desiredPos);
+        } else {
+            arrowUpToSelectedPosition(desiredPos);
+        }
+    }
+
+    private void arrowDownToSelectedPosition(int position) {
+        int maxDowns = 20;
+        while(mListView.getSelectedItemPosition() < position && --maxDowns > 0) {
+            mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        if (position != mListView.getSelectedItemPosition()) {
+            throw new IllegalStateException("couldn't get to item after 20 downs");
+        }
+
+    }
+
+    private void arrowUpToSelectedPosition(int position) {
+        int maxUps = 20;
+        while(mListView.getSelectedItemPosition() > position && --maxUps > 0) {
+            mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
+        }
+        if (position != mListView.getSelectedItemPosition()) {
+            throw new IllegalStateException("couldn't get to item after 20 ups");
+        }
+    }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ScrollViewScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ScrollViewScenario.java
new file mode 100644
index 0000000..aa17194
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ScrollViewScenario.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.util;
+
+import com.google.android.collect.Lists;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.util.List;
+
+/**
+ * Utility base class for creating scroll view scenarios, allowing you to add
+ * a series of different kinds of views arranged vertically, taking up a
+ * specified amount of the screen height.
+ */
+public abstract class ScrollViewScenario extends Activity {
+
+    /**
+     * Holds content of scroll view
+     */
+    private LinearLayout mLinearLayout;
+
+    /**
+     * The actual scroll view
+     */
+    private ScrollView mScrollView;
+
+
+    /**
+     * What we need of each view that the user wants: the view, and the ratio
+     * to the screen height for its desired height.
+     */
+    private interface ViewFactory {
+        View create(final Context context);
+
+        float getHeightRatio();
+    }
+
+    /**
+     * Partially implement ViewFactory given a height ratio.
+     */
+    private static abstract class ViewFactoryBase implements ViewFactory {
+
+        private float mHeightRatio;
+
+        @SuppressWarnings({"UnusedDeclaration"})
+        private ViewFactoryBase() {throw new UnsupportedOperationException("don't call this!");}
+
+        protected ViewFactoryBase(float heightRatio) {
+            mHeightRatio = heightRatio;
+        }
+
+        public float getHeightRatio() {
+            return mHeightRatio;
+        }
+    }
+
+    /**
+     * Builder for selecting the views to be vertically arranged in the scroll
+     * view.
+     */
+    @SuppressWarnings({"JavaDoc"})
+    public static class Params {
+
+        List<ViewFactory> mViewFactories = Lists.newArrayList();
+
+        /**
+         * Add a text view.
+         * @param text The text of the text view.
+         * @param heightRatio The view's height will be this * the screen height.
+         */
+        public Params addTextView(final String text, float heightRatio) {
+            mViewFactories.add(new ViewFactoryBase(heightRatio) {
+                public View create(final Context context) {
+                    final TextView tv = new TextView(context);
+                    tv.setText(text);
+                    return tv;
+                }
+            });
+            return this;
+        }
+
+        /**
+         * Add multiple text views.
+         * @param numViews the number of views to add.
+         * @param textPrefix The text to prepend to each text view.
+         * @param heightRatio The view's height will be this * the screen height.
+         */
+        public Params addTextViews(int numViews, String textPrefix, float heightRatio) {
+            for (int i = 0; i < numViews; i++) {
+                addTextView(textPrefix + i, heightRatio);
+            }
+            return this;
+        }
+
+        /**
+         * Add a button.
+         * @param text The text of the button.
+         * @param heightRatio The view's height will be this * the screen height.
+         */
+        public Params addButton(final String text, float heightRatio) {
+            mViewFactories.add(new ViewFactoryBase(heightRatio) {
+                public View create(final Context context) {
+                    final Button button = new Button(context);
+                    button.setText(text);
+                    return button;
+                }
+            });
+            return this;
+        }
+
+        /**
+         * Add multiple buttons.
+         * @param numButtons the number of views to add.
+         * @param textPrefix The text to prepend to each button.
+         * @param heightRatio The view's height will be this * the screen height.
+         */
+        public Params addButtons(int numButtons, String textPrefix, float heightRatio) {
+            for (int i = 0; i < numButtons; i++) {
+                addButton(textPrefix + i, heightRatio);
+            }
+            return this;
+        }
+
+        /**
+         * Add an {@link InternalSelectionView}.
+         * @param numRows The number of rows in the internal selection view.
+         * @param heightRatio The view's height will be this * the screen height.
+         */
+        public Params addInternalSelectionView(final int numRows, float heightRatio) {
+            mViewFactories.add(new ViewFactoryBase(heightRatio) {
+                public View create(final Context context) {
+                    return new InternalSelectionView(context, numRows, "isv");
+                }
+            });
+            return this;
+        }
+
+        /**
+         * Add a sublayout of buttons as a single child of the scroll view.
+         * @param numButtons The number of buttons in the sub layout
+         * @param heightRatio The layout's height will be this * the screen height.
+         */
+        public Params addVerticalLLOfButtons(final String prefix, final int numButtons, float heightRatio) {
+            mViewFactories.add(new ViewFactoryBase(heightRatio) {
+
+                public View create(Context context) {
+                    final LinearLayout ll = new LinearLayout(context);
+                    ll.setOrientation(LinearLayout.VERTICAL);
+
+                    // fill width, equally weighted on height
+                    final LinearLayout.LayoutParams lp =
+                            new LinearLayout.LayoutParams(
+                                    ViewGroup.LayoutParams.FILL_PARENT, 0, 1f);
+                    for (int i = 0; i < numButtons; i++) {
+                        final Button button = new Button(context);
+                        button.setText(prefix + i);
+                        ll.addView(button, lp);
+                    }
+
+                    return ll;
+                }
+            });
+            return this;
+        }
+    }
+
+    /**
+     * Override this and initialized the views in the scroll view.
+     * @param params Used to configure the contents of the scroll view.
+     */
+    protected abstract void init(Params params);
+
+    public LinearLayout getLinearLayout() {
+        return mLinearLayout;
+    }
+
+    public ScrollView getScrollView() {
+        return mScrollView;
+    }
+
+    /**
+     * Get the child contained within the vertical linear layout of the
+     * scroll view.
+     * @param index The index within the linear layout.
+     * @return the child within the vertical linear layout of the scroll view
+     *   at the specified index.
+     */
+    @SuppressWarnings({"unchecked"})
+    public <T extends View> T getContentChildAt(int index) {
+        return (T) mLinearLayout.getChildAt(index);
+    }
+
+    /**
+     * Hook for changing how scroll view's are created.
+     */
+    @SuppressWarnings({"JavaDoc"})
+    protected ScrollView createScrollView() {
+        return new ScrollView(this);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // for test stability, turn off title bar
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        int screenHeight = getWindowManager().getDefaultDisplay().getHeight()
+                - 25;
+        mLinearLayout = new LinearLayout(this);
+        mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+
+        // initialize params
+        final Params params = new Params();
+        init(params);
+
+        // create views specified by params
+        for (ViewFactory viewFactory : params.mViewFactories) {
+            final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.FILL_PARENT,
+                    (int) (viewFactory.getHeightRatio() * screenHeight));
+            mLinearLayout.addView(viewFactory.create(this), lp);
+        }
+
+        mScrollView = createScrollView();
+        mScrollView.addView(mLinearLayout, new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+        // no animation to speed up tests
+        mScrollView.setSmoothScrollingEnabled(false);
+
+        setContentView(mScrollView);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/TouchModeFlexibleAsserts.java b/tests/FrameworkTest/src/com/android/frameworktest/util/TouchModeFlexibleAsserts.java
new file mode 100644
index 0000000..66adb17
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/TouchModeFlexibleAsserts.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.util;
+
+import junit.framework.Assert;
+
+import android.test.InstrumentationTestCase;
+import android.test.TouchUtils;
+import android.view.View;
+
+/**
+ * When entering touch mode via touch, the tests can be flaky.  These asserts
+ * are more flexible (allowing up to MAX_ATTEMPTS touches to enter touch mode via touch or
+ * tap) until we can find a way to solve the flakiness.
+ */
+public class TouchModeFlexibleAsserts {
+
+    private static int MAX_ATTEMPTS = 2;
+
+    private static int MAX_DELAY_MILLIS = 2000;
+
+    public static void assertInTouchModeAfterClick(InstrumentationTestCase test, View viewToTouch) {
+        int numAttemptsAtTouchMode = 0;
+        while (numAttemptsAtTouchMode < MAX_ATTEMPTS &&
+                !viewToTouch.isInTouchMode()) {
+            TouchUtils.clickView(test, viewToTouch);
+            numAttemptsAtTouchMode++;
+        }
+        Assert.assertTrue("even after " + MAX_ATTEMPTS + " clicks, did not enter "
+                + "touch mode", viewToTouch.isInTouchMode());
+        //Assert.assertEquals("number of touches to enter touch mode", 1, numAttemptsAtTouchMode);
+    }
+
+    public static void assertInTouchModeAfterTap(InstrumentationTestCase test, View viewToTouch) {
+        int numAttemptsAtTouchMode = 0;
+        while (numAttemptsAtTouchMode < MAX_ATTEMPTS &&
+                !viewToTouch.isInTouchMode()) {
+            TouchUtils.tapView(test, viewToTouch);
+            numAttemptsAtTouchMode++;
+        }
+        Assert.assertTrue("even after " + MAX_ATTEMPTS + " taps, did not enter "
+                + "touch mode", viewToTouch.isInTouchMode());
+        //Assert.assertEquals("number of touches to enter touch mode", 1, numAttemptsAtTouchMode);
+    }
+
+    public static void assertNotInTouchModeAfterKey(InstrumentationTestCase test, int keyCode, View checkForTouchMode) {
+        test.sendKeys(keyCode);
+        int amountLeft = MAX_DELAY_MILLIS;
+
+        while (checkForTouchMode.isInTouchMode() && amountLeft > 0) {
+            amountLeft -= 200;
+            try {
+                Thread.sleep(200);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        Assert.assertFalse("even after waiting " + MAX_DELAY_MILLIS + " millis after " 
+                + "pressing key event, still in touch mode", checkForTouchMode.isInTouchMode());
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/BigCache.java b/tests/FrameworkTest/src/com/android/frameworktest/view/BigCache.java
new file mode 100644
index 0000000..6f5eb00
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/BigCache.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.view.ViewGroup;
+import android.view.View;
+import android.view.Display;
+import android.view.ViewConfiguration;
+
+/**
+ * This activity contains two Views, one as big as the screen, one much larger. The large one
+ * should not be able to activate its drawing cache.
+ */
+public class BigCache extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final LinearLayout testBed = new LinearLayout(this);
+        testBed.setOrientation(LinearLayout.VERTICAL);
+        testBed.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+        final int cacheSize = ViewConfiguration.getMaximumDrawingCacheSize();
+        final Display display = getWindowManager().getDefaultDisplay();
+        final int screenWidth = display.getWidth();
+        final int screenHeight = display.getHeight();
+
+        final View tiny = new View(this);
+        tiny.setId(R.id.a);
+        tiny.setBackgroundColor(0xFFFF0000);
+        tiny.setLayoutParams(new LinearLayout.LayoutParams(screenWidth, screenHeight));
+
+        final View large = new View(this);
+        large.setId(R.id.b);
+        large.setBackgroundColor(0xFF00FF00);
+        // Compute the height of the view assuming a cache size based on ARGB8888
+        final int height = 2 * (cacheSize / 2) / screenWidth;
+        large.setLayoutParams(new LinearLayout.LayoutParams(screenWidth, height));
+
+        final ScrollView scroller = new ScrollView(this);
+        scroller.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+
+        testBed.addView(tiny);
+        testBed.addView(large);
+        scroller.addView(testBed);
+
+        setContentView(scroller);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Disabled.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Disabled.java
new file mode 100644
index 0000000..1f1f4f4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Disabled.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.app.Activity;
+
+/**
+ * Exercise View's disabled state.
+ */
+public class Disabled extends Activity implements OnClickListener {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.disabled);
+
+        // Find our buttons
+        Button disabledButton = (Button) findViewById(R.id.disabledButton);
+        disabledButton.setEnabled(false);
+        
+        // Find our buttons
+        Button disabledButtonA = (Button) findViewById(R.id.disabledButtonA);
+        disabledButtonA.setOnClickListener(this);
+    }
+
+    public void onClick(View v) {
+        Button disabledButtonB = (Button) findViewById(R.id.disabledButtonB);
+        disabledButtonB.setEnabled(!disabledButtonB.isEnabled());
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/GlobalFocusChange.java b/tests/FrameworkTest/src/com/android/frameworktest/view/GlobalFocusChange.java
new file mode 100644
index 0000000..1cbf05a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/GlobalFocusChange.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewTreeObserver;
+import android.view.View;
+
+public class GlobalFocusChange extends Activity implements ViewTreeObserver.OnGlobalFocusChangeListener {
+    public View mOldFocus;
+    public View mNewFocus;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.focus_listener);
+        findViewById(R.id.left).getViewTreeObserver().addOnGlobalFocusChangeListener(this);
+    }
+
+    public void reset() {
+        mOldFocus = mNewFocus = null;
+    }
+
+    public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+        mOldFocus = oldFocus;
+        mNewFocus = newFocus;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Include.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Include.java
new file mode 100644
index 0000000..fc36e37
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Include.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+
+/**
+ * Exercise <include /> tag in XML files.
+ */
+public class Include extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.include_tag);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Longpress.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Longpress.java
new file mode 100644
index 0000000..f3483fc
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Longpress.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Longpress extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.longpress);
+    }
+}
+
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Merge.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Merge.java
new file mode 100644
index 0000000..9596e91
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Merge.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.widget.LinearLayout;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+
+/**
+ * Exercise <merge /> tag in XML files.
+ */
+public class Merge extends Activity {
+    private LinearLayout mLayout;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        LayoutInflater.from(this).inflate(R.layout.merge_tag, mLayout);
+
+        setContentView(mLayout);
+    }
+
+    public ViewGroup getLayout() {
+        return mLayout;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/PopupWindowVisibility.java b/tests/FrameworkTest/src/com/android/frameworktest/view/PopupWindowVisibility.java
new file mode 100644
index 0000000..f4d477d4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/PopupWindowVisibility.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.Button;
+import android.widget.Spinner;
+
+import com.android.frameworktest.R;
+
+/**
+ * Tests views with popupWindows becoming invisible
+ */
+public class PopupWindowVisibility extends Activity implements OnClickListener {
+    
+    private View mFrame;
+    private Button mHide;
+    private Button mShow;
+    
+
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.popup_window_visibility);
+
+        mFrame = findViewById(R.id.frame);
+        
+        mHide = (Button) findViewById(R.id.hide);
+        mHide.setOnClickListener(this);
+        
+        mShow = (Button) findViewById(R.id.show);
+        mShow.setOnClickListener(this);
+        
+        Spinner spinner = (Spinner) findViewById(R.id.spinner);
+        ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_spinner_item, mStrings);
+        spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spinner.setAdapter(spinnerAdapter);
+        
+        ArrayAdapter<String> autoAdapter = new ArrayAdapter<String>(this,
+                android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+        AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.auto);
+        textView.setAdapter(autoAdapter);
+    }
+
+
+    public void onClick(View v) {
+        mFrame.setVisibility(v == mHide ? View.INVISIBLE : View.VISIBLE);
+    }
+    private static final String[] mStrings = {
+        "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"
+        };
+    
+    static final String[] COUNTRIES = new String[] {
+        "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+        "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+        "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+        "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+        "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+        "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
+        "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
+        "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+        "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+        "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+        "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+        "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+        "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+        "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+        "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+        "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+        "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+        "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+        "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+        "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+        "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+        "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+        "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+        "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+        "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+        "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+        "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+        "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+        "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+        "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+        "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+        "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+        "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+        "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+        "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+        "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+        "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+        "Ukraine", "United Arab Emirates", "United Kingdom",
+        "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+        "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+        "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+        };
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/PreDrawListener.java b/tests/FrameworkTest/src/com/android/frameworktest/view/PreDrawListener.java
new file mode 100644
index 0000000..cb456b2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/PreDrawListener.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.frameworktest.R;
+
+
+/**
+ * Tests views with popupWindows becoming invisible
+ */
+public class PreDrawListener extends Activity implements OnClickListener {
+    
+    private MyLinearLayout mFrame;
+
+
+    static public class MyLinearLayout extends LinearLayout implements
+            ViewTreeObserver.OnPreDrawListener {
+
+        public boolean mCancelNextDraw;
+        
+        public MyLinearLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public MyLinearLayout(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onAttachedToWindow() {
+            super.onAttachedToWindow();
+            getViewTreeObserver().addOnPreDrawListener(this);
+        }
+        
+        public boolean onPreDraw() {
+            if (mCancelNextDraw) {
+                Button b = new Button(this.getContext());
+                b.setText("Hello");
+                addView(b, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
+                        LayoutParams.WRAP_CONTENT));
+                mCancelNextDraw = false;
+                return false;
+            }
+            return true;
+        }
+        
+    }
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.pre_draw_listener);
+
+        mFrame = (MyLinearLayout) findViewById(R.id.frame);
+
+        Button mGoButton = (Button) findViewById(R.id.go);
+        mGoButton.setOnClickListener(this);
+    }
+
+
+    public void onClick(View v) {
+        mFrame.mCancelNextDraw = true;
+        mFrame.invalidate();
+    }
+
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/RemoteViewsActivity.java b/tests/FrameworkTest/src/com/android/frameworktest/view/RemoteViewsActivity.java
new file mode 100644
index 0000000..146c0ab
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/RemoteViewsActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercise RemoteViews -- especially filtering
+ */
+public class RemoteViewsActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.remote_view_host);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/RunQueue.java b/tests/FrameworkTest/src/com/android/frameworktest/view/RunQueue.java
new file mode 100644
index 0000000..c8c3c28
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/RunQueue.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import com.android.frameworktest.R;
+
+/**
+ * Tests views using post*() and getViewTreeObserver() before onAttachedToWindow().
+ */
+public class RunQueue extends Activity implements ViewTreeObserver.OnGlobalLayoutListener {
+    public boolean runnableRan = false;
+    public boolean runnableCancelled = true;
+    public boolean globalLayout = false;
+    public ViewTreeObserver viewTreeObserver;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        TextView textView = new TextView(this);
+        textView.setText("RunQueue");
+        textView.setId(R.id.simple_view);
+
+        setContentView(textView);
+        final View view = findViewById(R.id.simple_view);
+
+        view.post(new Runnable() {
+            public void run() {
+                runnableRan = true;
+            }
+        });
+
+        final Runnable runnable = new Runnable() {
+            public void run() {
+                runnableCancelled = false;
+            }
+        };
+        view.post(runnable);
+        view.post(runnable);
+        view.post(runnable);
+        view.post(runnable);
+        view.removeCallbacks(runnable);
+
+        viewTreeObserver = view.getViewTreeObserver();
+        viewTreeObserver.addOnGlobalLayoutListener(this);
+    }
+
+    public void onGlobalLayout() {
+        globalLayout = true;
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/StubbedView.java b/tests/FrameworkTest/src/com/android/frameworktest/view/StubbedView.java
new file mode 100644
index 0000000..2b0db9d
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/StubbedView.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.view.View;
+
+/**
+ * Exercise <ViewStub /> tag in XML files.
+ */
+public class StubbedView extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.viewstub);
+
+        findViewById(R.id.vis).setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                final View view = findViewById(R.id.viewStub);
+                if (view != null) {
+                    view.setVisibility(View.VISIBLE);
+                }
+            }
+        });
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/ViewGroupChildren.java b/tests/FrameworkTest/src/com/android/frameworktest/view/ViewGroupChildren.java
new file mode 100644
index 0000000..163e03c
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/ViewGroupChildren.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.view.View;
+import android.app.Activity;
+
+/**
+ * Exercise ViewGroup's ability to add and remove children.
+ */
+public class ViewGroupChildren extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.viewgroupchildren);
+    }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Visibility.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Visibility.java
new file mode 100644
index 0000000..e068620
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Visibility.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.view.View;
+import android.app.Activity;
+
+/**
+ * Exercise View's ability to change their visibility: GONE, INVISIBLE and
+ * VISIBLE. 
+ */
+public class Visibility extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.visibility);
+
+        // Find the view whose visibility will change
+        mVictim = findViewById(R.id.victim);
+
+        // Find our buttons
+        Button visibleButton = (Button) findViewById(R.id.vis);
+        Button invisibleButton = (Button) findViewById(R.id.invis);
+        Button goneButton = (Button) findViewById(R.id.gone);
+
+        // Wire each button to a click listener
+        visibleButton.setOnClickListener(mVisibleListener);
+        invisibleButton.setOnClickListener(mInvisibleListener);
+        goneButton.setOnClickListener(mGoneListener);
+    }
+
+
+    View.OnClickListener mVisibleListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mVictim.setVisibility(View.VISIBLE);
+        }
+    };
+
+    View.OnClickListener mInvisibleListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mVictim.setVisibility(View.INVISIBLE);
+        }
+    };
+
+    View.OnClickListener mGoneListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mVictim.setVisibility(View.GONE);
+        }
+    };
+
+    private View mVictim;
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/ZeroSized.java b/tests/FrameworkTest/src/com/android/frameworktest/view/ZeroSized.java
new file mode 100644
index 0000000..e858fc0
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/ZeroSized.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+
+/**
+ * This activity contains Views with various widths and heights. The goal is to exercise the
+ * drawing cache when width is null, height is null or both.
+ */
+public class ZeroSized extends Activity {
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.zero_sized);
+    }
+}
diff --git a/tests/FrameworkTest/tests/Android.mk b/tests/FrameworkTest/tests/Android.mk
new file mode 100644
index 0000000..5c54684
--- /dev/null
+++ b/tests/FrameworkTest/tests/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := FrameworkTestTests
+
+LOCAL_INSTRUMENTATION_FOR := FrameworkTest
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/FrameworkTest/tests/AndroidManifest.xml b/tests/FrameworkTest/tests/AndroidManifest.xml
new file mode 100644
index 0000000..65aaebb
--- /dev/null
+++ b/tests/FrameworkTest/tests/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.frameworktest.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--
+    This declares that this app uses the instrumentation test runner targeting
+    the package of com.android.frameworktest.  To run the tests use the command:
+    "adb shell am instrument -w com.android.frameworktest.tests/android.test.InstrumentationTestRunner"
+    -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.frameworktest"
+                     android:label="framework tests"/>
+
+</manifest>
diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
new file mode 100644
index 0000000..aa3d186
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
@@ -0,0 +1,578 @@
+package android.content;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.test.AndroidTestCase;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.SortedSet;
+
+/** Unit test for {@link android.content.AbstractTableMerger}. */
+public class AbstractTableMergerTest extends AndroidTestCase {
+    MockSyncableContentProvider mRealProvider;
+    MockSyncableContentProvider mTempProvider;
+    MockTableMerger mMerger;
+    MockSyncContext mSyncContext;
+
+    static final String TABLE_NAME = "items";
+    static final String DELETED_TABLE_NAME = "deleted_items";
+    static final Uri CONTENT_URI = Uri.parse("content://testdata");
+    static final Uri TABLE_URI = Uri.withAppendedPath(CONTENT_URI, TABLE_NAME);
+    static final Uri DELETED_TABLE_URI = Uri.withAppendedPath(CONTENT_URI, DELETED_TABLE_NAME);
+
+    private final String ACCOUNT = "account@goo.com";
+
+    private final ArrayList<Expectation> mExpectations = Lists.newArrayList();
+
+    static class Expectation {
+        enum Type {
+            UPDATE,
+            INSERT,
+            DELETE,
+            RESOLVE
+        }
+
+        Type mType;
+        ContentValues mValues;
+        Long mLocalRowId;
+
+        Expectation(Type type, Long localRowId, ContentValues values) {
+            mType = type;
+            mValues = values;
+            mLocalRowId = localRowId;
+            if (type == Type.DELETE) {
+                assertNull(values);
+            } else {
+                assertFalse(values.containsKey("_id"));
+            }
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mSyncContext = new MockSyncContext();
+        mRealProvider = new MockSyncableContentProvider();
+        mTempProvider = mRealProvider.getTemporaryInstance();
+        mMerger = new MockTableMerger(mRealProvider.getDatabase(),
+                TABLE_NAME, TABLE_URI, DELETED_TABLE_NAME, DELETED_TABLE_URI);
+        mExpectations.clear();
+    }
+
+    ContentValues newValues(String data, String syncId, String syncAccount,
+            String syncTime, String syncVersion, Long syncLocalId) {
+        ContentValues values = new ContentValues();
+        if (data != null) values.put("data", data);
+        if (syncTime != null) values.put("_sync_time", syncTime);
+        if (syncVersion != null) values.put("_sync_version", syncVersion);
+        if (syncId != null) values.put("_sync_id", syncId);
+        if (syncAccount != null) values.put("_sync_account", syncAccount);
+        values.put("_sync_local_id", syncLocalId);
+        values.put("_sync_dirty", 0);
+        return values;
+    }
+
+    ContentValues newDeletedValues(String syncId, String syncAccount, String syncVersion,
+            Long syncLocalId) {
+        ContentValues values = new ContentValues();
+        if (syncVersion != null) values.put("_sync_version", syncVersion);
+        if (syncId != null) values.put("_sync_id", syncId);
+        if (syncAccount != null) values.put("_sync_account", syncAccount);
+        if (syncLocalId != null) values.put("_sync_local_id", syncLocalId);
+        return values;
+    }
+
+    ContentValues newModifyData(String data) {
+        ContentValues values = new ContentValues();
+        values.put("data", data);
+        values.put("_sync_dirty", 1);
+        return values;
+    }
+
+    // Want to test adding, changing, deleting entries to a provider that has extra entries
+    // before and after the entries being changed.
+    public void testInsert() {
+        // add rows to the real provider
+        // add new row to the temp provider
+        final ContentValues row1 = newValues("d1", "si1", ACCOUNT, "st1", "sv1", null);
+        mTempProvider.insert(TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.INSERT, null /* syncLocalId */, row1));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    public void testUpdateWithLocalId() {
+        // add rows to the real provider
+        // add new row to the temp provider that matches an unsynced row in the real provider
+        final ContentValues row1 = newValues("d1", "si1", ACCOUNT, "st1", "sv1", 11L);
+        mTempProvider.insert(TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.UPDATE, 11L, row1));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    public void testUpdateWithoutLocalId() {
+        // add rows to the real provider
+        Uri i1 = mRealProvider.insert(TABLE_URI,
+                newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+
+        // add new row to the temp provider that matches an unsynced row in the real provider
+        final ContentValues row1 = newValues("d2", "si1", ACCOUNT, "st2", "sv2", null);
+        mTempProvider.insert(TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.UPDATE, ContentUris.parseId(i1), row1));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    public void testResolve() {
+        // add rows to the real provider
+        Uri i1 = mRealProvider.insert(TABLE_URI,
+                newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+        mRealProvider.update(TABLE_URI, newModifyData("d2"), null, null);
+
+        // add row to the temp provider that matches a dirty, synced row in the real provider
+        final ContentValues row1 = newValues("d3", "si1", ACCOUNT, "st2", "sv2", null);
+        mTempProvider.insert(TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.RESOLVE, ContentUris.parseId(i1), row1));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    public void testResolveWithLocalId() {
+        // add rows to the real provider
+        Uri i1 = mRealProvider.insert(TABLE_URI,
+                newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+        mRealProvider.update(TABLE_URI, newModifyData("d2"), null, null);
+
+        // add row to the temp provider that matches a dirty, synced row in the real provider
+        ContentValues row1 = newValues("d2", "si1", ACCOUNT, "st2", "sv2", ContentUris.parseId(i1));
+        mTempProvider.insert(TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.UPDATE, ContentUris.parseId(i1), row1));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    public void testDeleteRowAfterDelete() {
+        // add rows to the real provider
+        Uri i1 = mRealProvider.insert(TABLE_URI,
+                newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+
+        // add a deleted record to the temp provider
+        ContentValues row1 = newDeletedValues(null, null, null, ContentUris.parseId(i1));
+        mTempProvider.insert(DELETED_TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.DELETE, ContentUris.parseId(i1), null));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    public void testDeleteRowAfterInsert() {
+        // add rows to the real provider
+        Uri i1 = mRealProvider.insert(TABLE_URI, newModifyData("d1"));
+
+        // add a deleted record to the temp provider
+        ContentValues row1 = newDeletedValues(null, null, null, ContentUris.parseId(i1));
+        mTempProvider.insert(DELETED_TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.DELETE, ContentUris.parseId(i1), null));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    public void testDeleteRowAfterUpdate() {
+        // add rows to the real provider
+        Uri i1 = mRealProvider.insert(TABLE_URI,
+                newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+
+        // add a deleted record to the temp provider
+        ContentValues row1 = newDeletedValues("si1", ACCOUNT, "sv1", ContentUris.parseId(i1));
+        mTempProvider.insert(DELETED_TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.DELETE, ContentUris.parseId(i1), null));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    public void testDeleteRowFromServer() {
+        // add rows to the real provider
+        Uri i1 = mRealProvider.insert(TABLE_URI,
+                newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+
+        // add a deleted record to the temp provider
+        ContentValues row1 = newDeletedValues("si1", ACCOUNT, "sv1", null);
+        mTempProvider.insert(DELETED_TABLE_URI, row1);
+
+        // add expected callbacks to merger
+        mExpectations.add(new Expectation(Expectation.Type.DELETE, ContentUris.parseId(i1), null));
+
+        // run merger
+        SyncResult syncResult = new SyncResult();
+        mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+        // check that all expectations were met
+        assertEquals("not all expectations were met", 0, mExpectations.size());
+    }
+
+    class MockTableMerger extends AbstractTableMerger {
+        public MockTableMerger(SQLiteDatabase database, String table, Uri tableURL,
+                String deletedTable, Uri deletedTableURL) {
+            super(database, table, tableURL, deletedTable, deletedTableURL);
+        }
+
+        public void insertRow(ContentProvider diffs, Cursor diffsCursor) {
+            Expectation expectation = mExpectations.remove(0);
+            checkExpectation(expectation,
+                    Expectation.Type.INSERT, null /* syncLocalId */, diffsCursor);
+        }
+
+        public void updateRow(long localPersonID, ContentProvider diffs, Cursor diffsCursor) {
+            Expectation expectation = mExpectations.remove(0);
+            checkExpectation(expectation, Expectation.Type.UPDATE, localPersonID, diffsCursor);
+        }
+
+        public void resolveRow(long localPersonID, String syncID, ContentProvider diffs,
+                Cursor diffsCursor) {
+            Expectation expectation = mExpectations.remove(0);
+            checkExpectation(expectation, Expectation.Type.RESOLVE, localPersonID, diffsCursor);
+        }
+
+        @Override
+        public void deleteRow(Cursor cursor) {
+            Expectation expectation = mExpectations.remove(0);
+            assertEquals(expectation.mType, Expectation.Type.DELETE);
+            assertNotNull(expectation.mLocalRowId);
+            final long localRowId = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
+            assertEquals((long)expectation.mLocalRowId, localRowId);
+            cursor.moveToNext();
+            mDb.delete(TABLE_NAME, "_id=" + localRowId, null);
+        }
+
+        protected void notifyChanges() {
+            throw new UnsupportedOperationException();
+        }
+
+        void checkExpectation(Expectation expectation,
+                Expectation.Type actualType, Long localRowId,
+                Cursor cursor) {
+            assertEquals(expectation.mType, actualType);
+            assertEquals(expectation.mLocalRowId, localRowId);
+
+            final SortedSet<String> actualKeys = Sets.newSortedSet(cursor.getColumnNames());
+            final SortedSet<String> expectedKeys = Sets.newSortedSet();
+            for (Map.Entry<String, Object> entry : expectation.mValues.valueSet()) {
+                expectedKeys.add(entry.getKey());
+            }
+            actualKeys.remove("_id");
+            actualKeys.remove("_sync_mark");
+            actualKeys.remove("_sync_local_id");
+            expectedKeys.remove("_sync_local_id");
+            expectedKeys.remove("_id");
+            assertEquals("column mismatch",
+                    TextUtils.join(",", expectedKeys), TextUtils.join(",", actualKeys));
+
+//            if (localRowId != null) {
+//                assertEquals((long) localRowId,
+//                        cursor.getLong(cursor.getColumnIndexOrThrow("_sync_local_id")));
+//            } else {
+//                assertTrue("unexpected _sync_local_id, "
+//                        + cursor.getLong(cursor.getColumnIndexOrThrow("_sync_local_id")),
+//                        cursor.isNull(cursor.getColumnIndexOrThrow("_sync_local_id")));
+//            }
+
+            for (String name : cursor.getColumnNames()) {
+                if ("_id".equals(name)) {
+                    continue;
+                }
+                if (cursor.isNull(cursor.getColumnIndexOrThrow(name))) {
+                    assertNull(expectation.mValues.getAsString(name));
+                } else {
+                    String actualValue =
+                            cursor.getString(cursor.getColumnIndexOrThrow(name));
+                    assertEquals("mismatch on column " + name,
+                            expectation.mValues.getAsString(name), actualValue);
+                }
+            }
+        }
+    }
+
+    class MockSyncableContentProvider extends SyncableContentProvider {
+        SQLiteDatabase mDb;
+        boolean mIsTemporary;
+        boolean mContainsDiffs;
+
+        private final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+        private static final int MATCHER_ITEMS = 0;
+        private static final int MATCHER_DELETED_ITEMS = 1;
+
+        public MockSyncableContentProvider() {
+            mIsTemporary = false;
+            setContainsDiffs(false);
+            sURIMatcher.addURI(CONTENT_URI.getAuthority(), "items", MATCHER_ITEMS);
+            sURIMatcher.addURI(CONTENT_URI.getAuthority(), "deleted_items", MATCHER_DELETED_ITEMS);
+
+            mDb = SQLiteDatabase.create(null);
+            mDb.execSQL("CREATE TABLE items ("
+                    + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + "data TEXT, "
+                    + "_sync_time TEXT, "
+                    + "_sync_version TEXT, "
+                    + "_sync_id TEXT, "
+                    + "_sync_local_id INTEGER, "
+                    + "_sync_dirty INTEGER NOT NULL DEFAULT 0, "
+                    + "_sync_account TEXT, "
+                    + "_sync_mark INTEGER)");
+
+            mDb.execSQL("CREATE TABLE deleted_items ("
+                    + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + "_sync_version TEXT, "
+                    + "_sync_id TEXT, "
+                    + "_sync_local_id INTEGER, "
+                    + "_sync_account TEXT, "
+                    + "_sync_mark INTEGER)");
+        }
+
+        public boolean onCreate() {
+            throw new UnsupportedOperationException();
+        }
+
+        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+                String sortOrder) {
+            int match = sURIMatcher.match(uri);
+            switch (match) {
+                case MATCHER_ITEMS:
+                    return mDb.query(TABLE_NAME, projection, selection, selectionArgs,
+                            null, null, sortOrder);
+                case MATCHER_DELETED_ITEMS:
+                    return mDb.query(DELETED_TABLE_NAME, projection, selection, selectionArgs,
+                            null, null, sortOrder);
+                default:
+                    throw new UnsupportedOperationException("Cannot query URL: " + uri);
+            }
+        }
+
+        public String getType(Uri uri) {
+            throw new UnsupportedOperationException();
+        }
+
+        public Uri insert(Uri uri, ContentValues values) {
+            int match = sURIMatcher.match(uri);
+            switch (match) {
+                case MATCHER_ITEMS: {
+                    long id = mDb.insert(TABLE_NAME, "_id", values);
+                    return CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
+                }
+                case MATCHER_DELETED_ITEMS: {
+                    long id = mDb.insert(DELETED_TABLE_NAME, "_id", values);
+                    return CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
+                }
+                default:
+                    throw new UnsupportedOperationException("Cannot query URL: " + uri);
+            }
+        }
+
+        public int delete(Uri uri, String selection, String[] selectionArgs) {
+            int match = sURIMatcher.match(uri);
+            switch (match) {
+                case MATCHER_ITEMS:
+                    return mDb.delete(TABLE_NAME, selection, selectionArgs);
+                case MATCHER_DELETED_ITEMS:
+                    return mDb.delete(DELETED_TABLE_NAME, selection, selectionArgs);
+                default:
+                    throw new UnsupportedOperationException("Cannot query URL: " + uri);
+            }
+        }
+
+        public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+            int match = sURIMatcher.match(uri);
+            switch (match) {
+                case MATCHER_ITEMS:
+                    return mDb.update(TABLE_NAME, values, selection, selectionArgs);
+                case MATCHER_DELETED_ITEMS:
+                    return mDb.update(DELETED_TABLE_NAME, values, selection, selectionArgs);
+                default:
+                    throw new UnsupportedOperationException("Cannot query URL: " + uri);
+            }
+        }
+
+        protected boolean isTemporary() {
+            return mIsTemporary;
+        }
+
+        public void close() {
+            throw new UnsupportedOperationException();
+        }
+
+        protected void bootstrapDatabase(SQLiteDatabase db) {
+            throw new UnsupportedOperationException();
+        }
+
+        protected boolean upgradeDatabase(SQLiteDatabase db, int oldVersion, int newVersion) {
+            throw new UnsupportedOperationException();
+        }
+
+        protected void onDatabaseOpened(SQLiteDatabase db) {
+            throw new UnsupportedOperationException();
+        }
+
+        public MockSyncableContentProvider getTemporaryInstance() {
+            MockSyncableContentProvider temp = new MockSyncableContentProvider();
+            temp.mIsTemporary = true;
+            temp.setContainsDiffs(true);
+            return temp;
+        }
+
+        public SQLiteDatabase getDatabase() {
+            return mDb;
+        }
+
+        public boolean getContainsDiffs() {
+            return mContainsDiffs;
+        }
+
+        public void setContainsDiffs(boolean containsDiffs) {
+            mContainsDiffs = containsDiffs;
+        }
+
+        protected Iterable<? extends AbstractTableMerger> getMergers() {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean changeRequiresLocalSync(Uri uri) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void onSyncStart(SyncContext context, String account) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void onSyncStop(SyncContext context, boolean success) {
+            throw new UnsupportedOperationException();
+        }
+
+        public String getSyncingAccount() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void merge(SyncContext context, SyncableContentProvider diffs,
+                TempProviderSyncResult result, SyncResult syncResult) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void onSyncCanceled() {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean isMergeCancelled() {
+            return false;
+        }
+
+        protected int updateInternal(Uri url, ContentValues values, String selection,
+                String[] selectionArgs) {
+            throw new UnsupportedOperationException();
+        }
+
+        protected int deleteInternal(Uri url, String selection, String[] selectionArgs) {
+            throw new UnsupportedOperationException();
+        }
+
+        protected Uri insertInternal(Uri url, ContentValues values) {
+            throw new UnsupportedOperationException();
+        }
+
+        protected Cursor queryInternal(Uri url, String[] projection, String selection,
+                String[] selectionArgs, String sortOrder) {
+            throw new UnsupportedOperationException();
+        }
+
+        protected void onAccountsChanged(String[] accountsArray) {
+            throw new UnsupportedOperationException();
+        }
+
+        protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts, String table,
+                String accountColumnName) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void wipeAccount(String account) {
+            throw new UnsupportedOperationException();
+        }
+
+        public byte[] readSyncDataBytes(String account) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void writeSyncDataBytes(String account, byte[] data) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    class MockSyncContext extends SyncContext {
+        public MockSyncContext() {
+            super(null);
+        }
+
+        @Override
+        public void setStatusText(String message) {
+        }
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/android/content/SearchRecentSuggestionsProviderTest.java b/tests/FrameworkTest/tests/src/android/content/SearchRecentSuggestionsProviderTest.java
new file mode 100644
index 0000000..a4c33f5
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/content/SearchRecentSuggestionsProviderTest.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2008 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.content;
+
+import android.app.SearchManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.SearchRecentSuggestions;
+import android.test.ProviderTestCase2;
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Very simple provider that I can instantiate right here.
+ */
+class TestProvider extends SearchRecentSuggestionsProvider {
+    final static String AUTHORITY = "android.content.TestProvider";
+    final static int MODE = DATABASE_MODE_QUERIES + DATABASE_MODE_2LINES;
+    
+    public TestProvider() {
+        super();
+        setupSuggestions(AUTHORITY, MODE);
+    }
+}
+
+/**
+ * ProviderTestCase that performs unit tests of SearchRecentSuggestionsProvider.
+ * 
+ * You can run this test in isolation via the commands:
+ * 
+ * $ (cd tests/FrameworkTests/ && mm) && adb sync
+ * $ adb shell am instrument -w \
+ *     -e class android.content.SearchRecentSuggestionsProviderTest 
+ *     com.android.frameworktest.tests/android.test.InstrumentationTestRunner
+ */
+// Suppress these until bug http://b/issue?id=1416586 is fixed.
+@Suppress
+public class SearchRecentSuggestionsProviderTest extends ProviderTestCase2<TestProvider> {
+
+    // Elements prepared by setUp()
+    SearchRecentSuggestions mSearchHelper;
+    
+    public SearchRecentSuggestionsProviderTest() {
+        super(TestProvider.class, TestProvider.AUTHORITY);
+    }
+    
+    /**
+     * During setup, grab a helper for DB access 
+     */
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        // Use the recent suggestions helper.  As long as we pass in our isolated context,
+        // it should correctly access the provider under test.
+        mSearchHelper = new SearchRecentSuggestions(getMockContext(), 
+                TestProvider.AUTHORITY, TestProvider.MODE);
+
+        // test for empty database at setup time
+        checkOpenCursorCount(0);
+    }
+    
+    /**
+     * Simple test to see if we can instantiate the whole mess.
+     */
+    public void testSetup() {
+        assertTrue(true);
+    }
+    
+    /**
+     * Simple test to see if we can write and read back a single query
+     */
+    public void testOneQuery() {
+        final String TEST_LINE1 = "test line 1";
+        final String TEST_LINE2 = "test line 2";
+        mSearchHelper.saveRecentQuery(TEST_LINE1, TEST_LINE2);
+        
+        // make sure that there are is exactly one entry returned by a non-filtering cursor
+        checkOpenCursorCount(1);
+        
+        // test non-filtering cursor for correct entry
+        checkResultCounts(null, 1, 1, TEST_LINE1, TEST_LINE2);
+        
+        // test filtering cursor for correct entry
+        checkResultCounts(TEST_LINE1, 1, 1, TEST_LINE1, TEST_LINE2);
+        checkResultCounts(TEST_LINE2, 1, 1, TEST_LINE1, TEST_LINE2);
+        
+        // test that a different filter returns zero results
+        checkResultCounts("bad filter", 0, 0, null, null);
+    }
+    
+    /** 
+     * Simple test to see if we can write and read back a diverse set of queries
+     */
+    public void testMixedQueries() {
+        // we'll make 10 queries named "query x" and 10 queries named "test x"
+        final String TEST_GROUP_1 = "query ";
+        final String TEST_GROUP_2 = "test ";
+        final String TEST_LINE2 = "line2 ";
+        final int GROUP_COUNT = 10;
+        
+        writeEntries(GROUP_COUNT, TEST_GROUP_1, TEST_LINE2);
+        writeEntries(GROUP_COUNT, TEST_GROUP_2, TEST_LINE2);
+        
+        // check counts
+        checkOpenCursorCount(2 * GROUP_COUNT);
+        
+        // check that each query returns the right result counts
+        checkResultCounts(TEST_GROUP_1, GROUP_COUNT, GROUP_COUNT, null, null);
+        checkResultCounts(TEST_GROUP_2, GROUP_COUNT, GROUP_COUNT, null, null);
+        checkResultCounts(TEST_LINE2, 2 * GROUP_COUNT, 2 * GROUP_COUNT, null, null);
+    }
+    
+    /**
+     * Test that the reordering code works properly.  The most recently injected queries
+     * should replace existing queries and be sorted to the top of the list.
+     */
+    public void testReordering() {
+        // first we'll make 10 queries named "group1 x"
+        final int GROUP_1_COUNT = 10;
+        final String GROUP_1_QUERY = "group1 ";
+        final String GROUP_1_LINE2 = "line2 ";
+        writeEntries(GROUP_1_COUNT, GROUP_1_QUERY, GROUP_1_LINE2);
+        
+        // check totals
+        checkOpenCursorCount(GROUP_1_COUNT);
+
+        // guarantee that group 1 has older timestamps
+        writeDelay();
+        
+        // next we'll add 10 entries named "group2 x"
+        final int GROUP_2_COUNT = 10;
+        final String GROUP_2_QUERY = "group2 ";
+        final String GROUP_2_LINE2 = "line2 ";
+        writeEntries(GROUP_2_COUNT, GROUP_2_QUERY, GROUP_2_LINE2);
+        
+        // check totals
+        checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+
+        // guarantee that group 2 has older timestamps
+        writeDelay();
+        
+        // now refresh 5 of the 10 from group 1
+        // change line2 so they can be more easily tracked
+        final int GROUP_3_COUNT = 5;
+        final String GROUP_3_QUERY = GROUP_1_QUERY;
+        final String GROUP_3_LINE2 = "refreshed ";
+        writeEntries(GROUP_3_COUNT, GROUP_3_QUERY, GROUP_3_LINE2);
+        
+        // confirm that the total didn't change (those were replacements, not adds)
+        checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+        
+        // confirm that the are now 5 in group 1, 10 in group 2, and 5 in group 3
+        int newGroup1Count = GROUP_1_COUNT - GROUP_3_COUNT;
+        checkResultCounts(GROUP_1_QUERY, newGroup1Count, newGroup1Count, null, GROUP_1_LINE2);
+        checkResultCounts(GROUP_2_QUERY, GROUP_2_COUNT, GROUP_2_COUNT, null, null);
+        checkResultCounts(GROUP_3_QUERY, GROUP_3_COUNT, GROUP_3_COUNT, null, GROUP_3_LINE2);
+        
+        // finally, spot check that the right groups are in the right places
+        // the ordering should be group 3 (newest), group 2, group 1 (oldest)
+        Cursor c = getQueryCursor(null);
+        int colQuery = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_QUERY);
+        int colDisplay1 = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1);
+        int colDisplay2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
+
+        // Spot check the first and last expected entries of group 3
+        c.moveToPosition(0);
+        assertTrue("group 3 did not properly reorder to head of list",
+                checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_3_QUERY, GROUP_3_LINE2));
+        c.move(GROUP_3_COUNT - 1);
+        assertTrue("group 3 did not properly reorder to head of list",
+                checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_3_QUERY, GROUP_3_LINE2));
+
+        // Spot check the first and last expected entries of group 2
+        c.move(1);
+        assertTrue("group 2 not in expected position after reordering",
+                checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_2_QUERY, GROUP_2_LINE2));
+        c.move(GROUP_2_COUNT - 1);
+        assertTrue("group 2 not in expected position after reordering",
+                checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_2_QUERY, GROUP_2_LINE2));
+
+        // Spot check the first and last expected entries of group 1
+        c.move(1);
+        assertTrue("group 1 not in expected position after reordering",
+                checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_1_QUERY, GROUP_1_LINE2));
+        c.move(newGroup1Count - 1);
+        assertTrue("group 1 not in expected position after reordering",
+                checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_1_QUERY, GROUP_1_LINE2));
+        
+        c.close();
+    }
+    
+    /**
+     * Test that the pruning code works properly,  The database should not go beyond 250 entries,
+     * and the oldest entries should always be discarded first. 
+     * 
+     * TODO:  This is a slow test, do we have annotation for that?
+     */
+    public void testPruning() {
+        // first we'll make 50 queries named "group1 x"
+        final int GROUP_1_COUNT = 50;
+        final String GROUP_1_QUERY = "group1 ";
+        final String GROUP_1_LINE2 = "line2 ";
+        writeEntries(GROUP_1_COUNT, GROUP_1_QUERY, GROUP_1_LINE2);
+        
+        // check totals
+        checkOpenCursorCount(GROUP_1_COUNT);
+
+        // guarantee that group 1 has older timestamps (and will be pruned first)
+        writeDelay();
+        
+        // next we'll add 200 entries named "group2 x"
+        final int GROUP_2_COUNT = 200;
+        final String GROUP_2_QUERY = "group2 ";
+        final String GROUP_2_LINE2 = "line2 ";
+        writeEntries(GROUP_2_COUNT, GROUP_2_QUERY, GROUP_2_LINE2);
+        
+        // check totals
+        checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+        
+        // Finally we'll add 10 more entries named "group3 x"
+        // These should push out 10 entries from group 1
+        final int GROUP_3_COUNT = 10;
+        final String GROUP_3_QUERY = "group3 ";
+        final String GROUP_3_LINE2 = "line2 ";
+        writeEntries(GROUP_3_COUNT, GROUP_3_QUERY, GROUP_3_LINE2);
+        
+        // total should still be 250
+        checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+
+        // there should be 40 group 1, 200 group 2, and 10 group 3
+        int group1NewCount = GROUP_1_COUNT-GROUP_3_COUNT;
+        checkResultCounts(GROUP_1_QUERY, group1NewCount, group1NewCount, null, null);
+        checkResultCounts(GROUP_2_QUERY, GROUP_2_COUNT, GROUP_2_COUNT, null, null);
+        checkResultCounts(GROUP_3_QUERY, GROUP_3_COUNT, GROUP_3_COUNT, null, null);
+    }
+    
+    /**
+     * Test that the clear history code works properly.
+     */
+    public void testClear() {
+        // first we'll make 10 queries named "group1 x"
+        final int GROUP_1_COUNT = 10;
+        final String GROUP_1_QUERY = "group1 ";
+        final String GROUP_1_LINE2 = "line2 ";
+        writeEntries(GROUP_1_COUNT, GROUP_1_QUERY, GROUP_1_LINE2);
+        
+        // next we'll add 10 entries named "group2 x"
+        final int GROUP_2_COUNT = 10;
+        final String GROUP_2_QUERY = "group2 ";
+        final String GROUP_2_LINE2 = "line2 ";
+        writeEntries(GROUP_2_COUNT, GROUP_2_QUERY, GROUP_2_LINE2);
+        
+        // check totals
+        checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+
+        // delete all
+        mSearchHelper.clearHistory();
+        
+        // check totals
+        checkOpenCursorCount(0);
+    }
+    
+    /**
+     * Write a sequence of queries into the database, with incrementing counters in the strings.
+     */
+    private void writeEntries(int groupCount, String line1Base, String line2Base) {
+        for (int i = 0; i < groupCount; i++) {
+            final String line1 = line1Base + i;
+            final String line2 = line2Base + i;
+            mSearchHelper.saveRecentQuery(line1, line2);
+        }
+    }
+    
+    /**
+     * A very slight delay to ensure that successive groups of queries in the DB cannot
+     * have the same timestamp.
+     */
+    private void writeDelay() {
+        try {
+            Thread.sleep(10);
+        } catch (InterruptedException e) {
+            fail("Interrupted sleep.");
+        }
+    }
+    
+    /**
+     * Access an "open" (no selection) suggestions cursor and confirm that it has the specified
+     * number of entries.
+     * 
+     * @param expectCount The expected number of entries returned by the cursor.
+     */
+    private void checkOpenCursorCount(int expectCount) {
+        Cursor c = getQueryCursor(null);
+        assertEquals(expectCount, c.getCount());
+        c.close();
+    }
+    
+    /**
+     * Set up a filter cursor and then scan it for specific results.
+     * 
+     * @param queryString The query string to apply.
+     * @param minRows The minimum number of matching rows that must be found.
+     * @param maxRows The maximum number of matching rows that must be found.
+     * @param matchDisplay1 If non-null, must match DISPLAY1 column if row counts as match
+     * @param matchDisplay2 If non-null, must match DISPLAY2 column if row counts as match
+     */
+    private void checkResultCounts(String queryString, int minRows, int maxRows,
+            String matchDisplay1, String matchDisplay2) {
+        
+        // get the cursor and apply sanity checks to result
+        Cursor c = getQueryCursor(queryString);
+        assertNotNull(c);
+        assertTrue("Insufficient rows in filtered cursor", c.getCount() >= minRows);
+        
+        // look for minimum set of columns (note, display2 is optional)
+        int colQuery = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_QUERY);
+        int colDisplay1 = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1);
+        int colDisplay2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
+
+        // now loop through rows and look for desired rows
+        int foundRows = 0;
+        c.moveToFirst();
+        while (!c.isAfterLast()) {
+            if (checkRow(c, colQuery, colDisplay1, colDisplay2, matchDisplay1, matchDisplay2)) {
+                foundRows++;
+            }            
+            c.moveToNext();
+        }
+
+        // now check the results
+        assertTrue(minRows <= foundRows);
+        assertTrue(foundRows <= maxRows);
+        
+        c.close();
+    }
+    
+    /**
+     * Check a single row for equality with target strings.
+     * 
+     * @param c The cursor, already moved to the row
+     * @param colQuery The column # containing the query.  The query must match display1.
+     * @param colDisp1 The column # containing display line 1.
+     * @param colDisp2 The column # containing display line 2, or -1 if no column
+     * @param matchDisplay1 If non-null, this must be the prefix of display1
+     * @param matchDisplay2 If non-null, this must be the prefix of display2
+     * @return Returns true if the row is a "match"
+     */
+    private boolean checkRow(Cursor c, int colQuery, int colDisp1, int colDisp2,
+            String matchDisplay1, String matchDisplay2) {
+        // Get the data from the row
+        String query = c.getString(colQuery);
+        String display1 = c.getString(colDisp1);
+        String display2 = (colDisp2 >= 0) ? c.getString(colDisp2) : null;
+        
+        assertEquals(query, display1);
+        boolean result = true;
+        if (matchDisplay1 != null) {
+            result = result && (display1 != null) && display1.startsWith(matchDisplay1);
+        }
+        if (matchDisplay2 != null) {
+            result = result && (display2 != null) && display2.startsWith(matchDisplay2);
+        }
+        
+        return result;
+    }
+
+    /**
+     * Generate a query cursor in a manner like the search dialog would.
+     * 
+     * @param queryString The search string, or, null for "all"
+     * @return Returns a cursor, or null if there was some problem.  Be sure to close the cursor
+     * when done with it.
+     */
+    private Cursor getQueryCursor(String queryString) {
+        ContentResolver cr = getMockContext().getContentResolver();
+
+        String uriStr = "content://" + TestProvider.AUTHORITY + 
+        '/' + SearchManager.SUGGEST_URI_PATH_QUERY;
+        Uri contentUri = Uri.parse(uriStr);
+
+        String[] selArgs = new String[] {queryString};
+
+        Cursor c = cr.query(contentUri, null, null, selArgs, null);
+
+        assertNotNull(c);
+        return c;
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java
new file mode 100644
index 0000000..93cb84a
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 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.widget;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class AutoCompleteTextViewCallbacks 
+        extends ActivityInstrumentationTestCase2<AutoCompleteTextViewSimple> {
+
+    public AutoCompleteTextViewCallbacks() {
+        super("com.android.frameworktest", AutoCompleteTextViewSimple.class);
+    }
+
+    /** Test that the initial popup of the suggestions does not select anything */
+    @MediumTest
+    public void testPopupNoSelection() {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+        
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+        
+        // now check for selection callbacks.  Nothing should be clicked or selected.
+        assertFalse("onItemClick should not be called", theActivity.mItemClickCalled);
+        assertFalse("onItemSelected should not be called", theActivity.mItemSelectedCalled);
+        
+        // arguably, this should be "false", because we aren't deselecting - we shouldn't
+        // really be calling it.  But it's not the end of the world, and we might wind up
+        // breaking something if we change this.
+        assertTrue("onNothingSelected should be called", theActivity.mNothingSelectedCalled);
+    }
+
+    /** Test that arrow-down into the popup calls the onSelected callback */
+    @MediumTest
+    public void testPopupEnterSelection() {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+        
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+        
+        // prepare to move down into the popup
+        theActivity.resetItemListeners();
+        sendKeys("DPAD_DOWN");
+        
+        // now check for selection callbacks.
+        assertFalse("onItemClick should not be called", theActivity.mItemClickCalled);
+        assertTrue("onItemSelected should be called", theActivity.mItemSelectedCalled);
+        assertEquals("onItemSelected position", 0, theActivity.mItemSelectedPosition);
+        assertFalse("onNothingSelected should not be called", theActivity.mNothingSelectedCalled);
+        
+        // try one more time - should move from 0 to 1
+        theActivity.resetItemListeners();
+        sendKeys("DPAD_DOWN");
+        
+        // now check for selection callbacks.
+        assertFalse("onItemClick should not be called", theActivity.mItemClickCalled);
+        assertTrue("onItemSelected should be called", theActivity.mItemSelectedCalled);
+        assertEquals("onItemSelected position", 1, theActivity.mItemSelectedPosition);
+        assertFalse("onNothingSelected should not be called", theActivity.mNothingSelectedCalled);
+    }
+
+    /** Test that arrow-up out of the popup calls the onNothingSelected callback */
+    @MediumTest
+    public void testPopupLeaveSelection() {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+        
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+        
+        // move down into the popup
+        sendKeys("DPAD_DOWN");
+        
+        // now move back up out of the popup
+        theActivity.resetItemListeners();
+        sendKeys("DPAD_UP");
+
+        // now check for selection callbacks.
+        assertFalse("onItemClick should not be called", theActivity.mItemClickCalled);
+        assertFalse("onItemSelected should not be called", theActivity.mItemSelectedCalled);
+        assertTrue("onNothingSelected should be called", theActivity.mNothingSelectedCalled);
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
new file mode 100644
index 0000000..663b7a4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008 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.widget;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * A collection of tests on aspects of the AutoCompleteTextView's popup
+ */
+public class AutoCompleteTextViewPopup
+        extends ActivityInstrumentationTestCase2<AutoCompleteTextViewSimple> {
+
+    public AutoCompleteTextViewPopup() {
+        super("com.android.frameworktest", AutoCompleteTextViewSimple.class);
+    }
+    
+    /** Test that we can move the selection and it responds as expected */
+    @MediumTest
+    public void testPopupSetListSelection() throws Throwable {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        final AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+        
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+        
+        // No initial selection
+        assertEquals("getListSelection(-1)", 
+                ListView.INVALID_POSITION, textView.getListSelection());
+        
+        // set and check
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                textView.setListSelection(0);
+            }
+        });
+        instrumentation.waitForIdleSync();
+        assertEquals("set selection to (0)", 0, textView.getListSelection());
+        
+        // Use movement to cross-check the movement
+        sendKeys("DPAD_DOWN");
+        assertEquals("move selection to (1)", 1, textView.getListSelection());
+    }
+    
+    /** Test that we can look at the selection as we move around */
+    @MediumTest
+    public void testPopupGetListSelection() {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+        
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+        
+        // No initial selection
+        assertEquals("getListSelection(-1)", 
+                ListView.INVALID_POSITION, textView.getListSelection());
+        
+        // check for selection position as expected
+        sendKeys("DPAD_DOWN");
+        assertEquals("move selection to (0)", 0, textView.getListSelection());
+        
+        // Repeat for one more movement
+        sendKeys("DPAD_DOWN");
+        assertEquals("move selection to (1)", 1, textView.getListSelection());
+    }
+    
+    /** Test that we can clear the selection */
+    @MediumTest
+    public void testPopupClearListSelection() throws Throwable {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        final AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+        
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+        
+        // No initial selection
+        assertEquals("getListSelection(-1)", 
+                ListView.INVALID_POSITION, textView.getListSelection());
+        
+        // check for selection position as expected
+        sendKeys("DPAD_DOWN");
+        assertEquals("getListSelection(0)", 0, textView.getListSelection());
+        
+        // clear it
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                textView.clearListSelection();
+            }
+        });
+        instrumentation.waitForIdleSync();
+        assertEquals("setListSelection(ListView.INVALID_POSITION)", 
+                ListView.INVALID_POSITION, textView.getListSelection());
+    }
+
+    /** Make sure we handle an empty adapter properly */
+    @MediumTest
+    public void testPopupNavigateNoAdapter() throws Throwable {
+        AutoCompleteTextViewSimple theActivity = getActivity();
+        final AutoCompleteTextView textView = theActivity.getTextView();
+        final Instrumentation instrumentation = getInstrumentation();
+
+        // focus and type
+        textView.requestFocus();
+        instrumentation.waitForIdleSync();
+        sendKeys("A");
+
+        // No initial selection
+        assertEquals("getListSelection(-1)",
+                ListView.INVALID_POSITION, textView.getListSelection());
+
+        // check for selection position as expected
+        sendKeys("DPAD_DOWN");
+        assertEquals("getListSelection(0)", 0, textView.getListSelection());
+
+        // Now get rid of the adapter
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                textView.setAdapter((ArrayAdapter<?>) null);
+            }
+        });
+        instrumentation.waitForIdleSync();
+
+        // now try moving "down" - nothing should happen since there's no longer an adapter
+        sendKeys("DPAD_DOWN");
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/android/widget/SimpleCursorAdapterTest.java b/tests/FrameworkTest/tests/src/android/widget/SimpleCursorAdapterTest.java
new file mode 100644
index 0000000..58f4ccb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/widget/SimpleCursorAdapterTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2008 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.widget;
+
+import com.android.internal.database.ArrayListCursor;
+import com.google.android.collect.Lists;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+/**
+ * This is a series of tests of basic API contracts for SimpleCursorAdapter.  It is
+ * incomplete and can use work.
+ * 
+ * NOTE:  This contract holds for underlying cursor types too and these should
+ * be extracted into a set of tests that can be run on any descendant of CursorAdapter.
+ */
+public class SimpleCursorAdapterTest extends AndroidTestCase {
+    
+    String[] mFrom;
+    int[] mTo;
+    int mLayout;
+    Context mContext;
+    
+    ArrayList<ArrayList> mData2x2;
+    Cursor mCursor2x2;
+    
+    /**
+     * Set up basic columns and cursor for the tests
+     */
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        // all the pieces needed for the various tests
+        mFrom = new String[]{"Column1", "Column2"};
+        mTo = new int[]{com.android.internal.R.id.text1, com.android.internal.R.id.text2};
+        mLayout = com.android.internal.R.layout.simple_list_item_2;
+        mContext = getContext();
+
+        // raw data for building a basic test cursor
+        mData2x2 = createTestList(2, 2);
+        mCursor2x2 = new ArrayListCursor(mFrom, mData2x2);
+    }
+    
+    /**
+     * Borrowed from CursorWindowTest.java
+     */
+    private ArrayList<ArrayList> createTestList(int rows, int cols) {
+        ArrayList<ArrayList> list = Lists.newArrayList();
+        Random generator = new Random();
+
+        for (int i = 0; i < rows; i++) {
+            ArrayList<Integer> col = Lists.newArrayList();
+            list.add(col);
+            for (int j = 0; j < cols; j++) {
+                // generate random number
+                Integer r = generator.nextInt();
+                col.add(r);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Test creating with a live cursor
+     */
+    @SmallTest
+    public void testCreateLive() {
+        SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
+        
+        // Now see if we can pull 2 rows from the adapter
+        assertEquals(2, ca.getCount());
+    }
+    
+    /**
+     * Test creating with a null cursor
+     */
+    @SmallTest
+    public void testCreateNull() {
+        SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, null, mFrom, mTo);
+        
+        // The adapter should report zero rows
+        assertEquals(0, ca.getCount());
+    }
+    
+    /**
+     * Test changeCursor() with live cursor
+     */
+    @SmallTest
+    public void testChangeCursorLive() {
+        SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
+        
+        // Now see if we can pull 2 rows from the adapter
+        assertEquals(2, ca.getCount());
+        
+        // now put in a different cursor (5 rows)
+        ArrayList<ArrayList> data2 = createTestList(5, 2);
+        Cursor c2 = new ArrayListCursor(mFrom, data2);
+        ca.changeCursor(c2);
+        
+        // Now see if we can pull 5 rows from the adapter
+        assertEquals(5, ca.getCount());
+    }
+    
+    /**
+     * Test changeCursor() with null cursor
+     */
+    @SmallTest
+    public void testChangeCursorNull() {
+        SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
+        
+        // Now see if we can pull 2 rows from the adapter
+        assertEquals(2, ca.getCount());
+        
+        // now put in null
+        ca.changeCursor(null);
+        
+        // The adapter should report zero rows
+        assertEquals(0, ca.getCount());
+    }
+    
+    /**
+     * Test changeCursor() with differing column layout.  This confirms that the Adapter can
+     * deal with cursors that have the same essential data (as defined by the original mFrom
+     * array) but it's OK if the physical structure of the cursor changes (columns rearranged).
+     */
+    @SmallTest
+    public void testChangeCursorColumns() {
+        TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, mCursor2x2, 
+                mFrom, mTo);
+        
+        // check columns of original - mFrom and mTo should line up
+        int[] columns = ca.getConvertedFrom();
+        assertEquals(columns[0], 0);
+        assertEquals(columns[1], 1);
+
+        // Now make a new cursor with similar data but rearrange the columns
+        String[] swappedFrom = new String[]{"Column2", "Column1"};
+        Cursor c2 = new ArrayListCursor(swappedFrom, mData2x2);
+        ca.changeCursor(c2);
+        assertEquals(2, ca.getCount());
+
+        // check columns to see if rearrangement tracked (should be swapped now)
+        columns = ca.getConvertedFrom();
+        assertEquals(columns[0], 1);
+        assertEquals(columns[1], 0);
+    }
+    
+    /**
+     * Test that you can safely construct with a null cursor *and* null to/from arrays.
+     * This is new functionality added in 12/2008.
+     */
+    @SmallTest
+    public void testNullConstructor() {
+        SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, null, null, null);
+        assertEquals(0, ca.getCount());
+    }
+    
+    /**
+     * Test going from a null cursor to a non-null cursor *and* setting the to/from arrays
+     * This is new functionality added in 12/2008.
+     */
+    @SmallTest
+    public void testChangeNullToMapped() {
+        TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, null, null, null);
+        assertEquals(0, ca.getCount());
+
+        ca.changeCursorAndColumns(mCursor2x2, mFrom, mTo);
+        assertEquals(2, ca.getCount());
+        
+        // check columns of original - mFrom and mTo should line up
+        int[] columns = ca.getConvertedFrom();
+        assertEquals(2, columns.length);
+        assertEquals(0, columns[0]);
+        assertEquals(1, columns[1]);
+        int[] viewIds = ca.getTo();
+        assertEquals(2, viewIds.length);
+        assertEquals(com.android.internal.R.id.text1, viewIds[0]);
+        assertEquals(com.android.internal.R.id.text2, viewIds[1]);
+    }
+    
+    /**
+     * Test going from one mapping to a different mapping
+     * This is new functionality added in 12/2008.
+     */
+    @SmallTest
+    public void testChangeMapping() {
+        TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, mCursor2x2, 
+                mFrom, mTo);
+        assertEquals(2, ca.getCount());
+
+        // Now create a new configuration with same cursor and just one column mapped
+        String[] singleFrom = new String[]{"Column1"};
+        int[] singleTo = new int[]{com.android.internal.R.id.text1};
+        ca.changeCursorAndColumns(mCursor2x2, singleFrom, singleTo);
+
+        // And examine the results, make sure they're still consistent
+        int[] columns = ca.getConvertedFrom();
+        assertEquals(1, columns.length);
+        assertEquals(0, columns[0]);
+        int[] viewIds = ca.getTo();
+        assertEquals(1, viewIds.length);
+        assertEquals(com.android.internal.R.id.text1, viewIds[0]);
+        
+        // And again, same cursor, different map
+        singleFrom = new String[]{"Column2"};
+        singleTo = new int[]{com.android.internal.R.id.text2};
+        ca.changeCursorAndColumns(mCursor2x2, singleFrom, singleTo);
+
+        // And examine the results, make sure they're still consistent
+        columns = ca.getConvertedFrom();
+        assertEquals(1, columns.length);
+        assertEquals(1, columns[0]);
+        viewIds = ca.getTo();
+        assertEquals(1, viewIds.length);
+        assertEquals(com.android.internal.R.id.text2, viewIds[0]);
+    }
+    
+    /**
+     * This is simply a way to sneak a look at the protected mFrom() array.  A more API-
+     * friendly way to do this would be to mock out a View and a ViewBinder and exercise
+     * it via those seams.
+     */
+    private static class TestSimpleCursorAdapter extends SimpleCursorAdapter {
+        
+        public TestSimpleCursorAdapter(Context context, int layout, Cursor c,
+                String[] from, int[] to) {
+            super(context, layout, c, from, to);
+        }
+
+        int[] getConvertedFrom() {
+            return mFrom;
+        }
+        
+        int[] getTo() {
+            return mTo;
+        }
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/AllTests.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/AllTests.java
new file mode 100644
index 0000000..e43ebb8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/AllTests.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 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.frameworktest;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import android.test.suitebuilder.TestSuiteBuilder;
+
+public class AllTests extends TestSuite {
+
+    public static Test suite() {
+        return new TestSuiteBuilder(AllTests.class)
+                .includeAllPackagesUnderHere()
+                .includePackages("android.content")
+                .includePackages("android.widget")
+                .build();
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/DrawableBgMinSizeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/DrawableBgMinSizeTest.java
new file mode 100644
index 0000000..ef6297d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/DrawableBgMinSizeTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.drawable;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.drawable.DrawableBgMinSize;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.graphics.drawable.Drawable;
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.widget.AbsoluteLayout;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * {@link DrawableBgMinSize} exercises Views to obey their background drawable's
+ * minimum sizes.
+ */
+public class DrawableBgMinSizeTest extends
+        ActivityInstrumentationTestCase<DrawableBgMinSize> {
+    private Button mChangeBackgroundsButton;
+    
+    private Drawable mBackgroundDrawable;
+    private Drawable mBigBackgroundDrawable;
+    
+    private TextView mTextView;
+    private LinearLayout mLinearLayout;
+    private RelativeLayout mRelativeLayout;
+    private FrameLayout mFrameLayout;
+    private AbsoluteLayout mAbsoluteLayout;
+    
+    public DrawableBgMinSizeTest() {
+        super("com.android.frameworktest", DrawableBgMinSize.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final DrawableBgMinSize a = getActivity();
+
+        mChangeBackgroundsButton = (Button) a.findViewById(R.id.change_backgrounds);
+        mBackgroundDrawable = a.getResources().getDrawable(R.drawable.drawable_background);
+        mBigBackgroundDrawable = a.getResources().getDrawable(R.drawable.big_drawable_background);
+        mTextView = (TextView) a.findViewById(R.id.text_view);
+        mLinearLayout = (LinearLayout) a.findViewById(R.id.linear_layout);
+        mRelativeLayout = (RelativeLayout) a.findViewById(R.id.relative_layout);
+        mFrameLayout = (FrameLayout) a.findViewById(R.id.frame_layout);
+        mAbsoluteLayout = (AbsoluteLayout) a.findViewById(R.id.absolute_layout);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mChangeBackgroundsButton);
+        assertNotNull(mBackgroundDrawable);
+        assertNotNull(mBigBackgroundDrawable);
+        assertNotNull(mTextView);
+        assertNotNull(mLinearLayout);
+        assertNotNull(mRelativeLayout);
+        assertNotNull(mFrameLayout);
+        assertNotNull(mAbsoluteLayout);
+    }
+    
+    public void doMinimumSizeTest(View view) throws Exception {
+        assertTrue(view.getClass().getSimpleName() + " should respect the background Drawable's minimum width",
+                view.getWidth() >= mBackgroundDrawable.getMinimumWidth());
+        assertTrue(view.getClass().getSimpleName() + " should respect the background Drawable's minimum height",
+                view.getHeight() >= mBackgroundDrawable.getMinimumHeight());
+    }
+
+    @MediumTest
+    public void testTextViewMinimumSize() throws Exception {
+        doMinimumSizeTest(mTextView);
+    }
+    
+    @MediumTest
+    public void testLinearLayoutMinimumSize() throws Exception {
+        doMinimumSizeTest(mLinearLayout);
+    }
+    
+    @MediumTest
+    public void testRelativeLayoutMinimumSize() throws Exception {
+        doMinimumSizeTest(mRelativeLayout);
+    }
+    
+    @MediumTest
+    public void testAbsoluteLayoutMinimumSize() throws Exception {
+        doMinimumSizeTest(mAbsoluteLayout);
+    }
+    
+    @MediumTest
+    public void testFrameLayoutMinimumSize() throws Exception {
+        doMinimumSizeTest(mFrameLayout);
+    }
+    
+    public void doDiffBgMinimumSizeTest(final View view) throws Exception {
+        // Change to the bigger backgrounds
+        TouchUtils.tapView(this, mChangeBackgroundsButton);
+
+        assertTrue(view.getClass().getSimpleName()
+                + " should respect the different bigger background Drawable's minimum width", view
+                .getWidth() >= mBigBackgroundDrawable.getMinimumWidth());
+        assertTrue(view.getClass().getSimpleName()
+                + " should respect the different bigger background Drawable's minimum height", view
+                .getHeight() >= mBigBackgroundDrawable.getMinimumHeight());
+    }
+
+    @MediumTest
+    public void testTextViewDiffBgMinimumSize() throws Exception {
+        doDiffBgMinimumSizeTest(mTextView);
+    }
+    
+    @MediumTest
+    public void testLinearLayoutDiffBgMinimumSize() throws Exception {
+        doDiffBgMinimumSizeTest(mLinearLayout);
+    }
+    
+    @MediumTest
+    public void testRelativeLayoutDiffBgMinimumSize() throws Exception {
+        doDiffBgMinimumSizeTest(mRelativeLayout);
+    }
+    
+    @MediumTest
+    public void testAbsoluteLayoutDiffBgMinimumSize() throws Exception {
+        doDiffBgMinimumSizeTest(mAbsoluteLayout);
+    }
+    
+    @MediumTest
+    public void testFrameLayoutDiffBgMinimumSize() throws Exception {
+        doDiffBgMinimumSizeTest(mFrameLayout);
+    }
+    
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java
new file mode 100644
index 0000000..53085ca
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2009 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.frameworktest.drawable;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+public class MutateDrawableTest extends ActivityInstrumentationTestCase2<MutateDrawable> {
+    private View mFirstButton;
+    private View mSecondButton;
+
+    public MutateDrawableTest() {
+        super("com.android.frameworktest", MutateDrawable.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mFirstButton = getActivity().findViewById(com.android.frameworktest.R.id.a);
+        mSecondButton = getActivity().findViewById(com.android.frameworktest.R.id.b);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mFirstButton);
+        assertNotNull(mSecondButton);
+        assertNotSame(mFirstButton.getBackground(), mSecondButton.getBackground());
+    }
+
+    @MediumTest
+    public void testDrawableCanMutate() throws Exception {
+        assertNotSame(mFirstButton.getBackground().getConstantState(),
+                mSecondButton.getBackground().getConstantState());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListBasicTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListBasicTest.java
new file mode 100644
index 0000000..163e084
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListBasicTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.expandablelistview;
+
+import com.android.frameworktest.expandablelistview.ExpandableListSimple;
+import com.android.frameworktest.util.ExpandableListScenario;
+import com.android.frameworktest.util.ListUtil;
+import com.android.frameworktest.util.ExpandableListScenario.MyGroup;
+
+import java.util.List;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+
+public class ExpandableListBasicTest extends ActivityInstrumentationTestCase<ExpandableListSimple> {
+    private ExpandableListScenario mActivity;
+    private ExpandableListView mListView;
+    private ExpandableListAdapter mAdapter;
+    private ListUtil mListUtil;
+    
+    public ExpandableListBasicTest() {
+        super("com.android.frameworktest",
+                ExpandableListSimple.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        mActivity = getActivity();
+        mListView = mActivity.getExpandableListView();
+        mAdapter = mListView.getExpandableListAdapter();
+        mListUtil = new ListUtil(mListView, getInstrumentation());
+    }
+    
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+    }
+    
+    private int expandGroup(int numChildren, boolean atLeastOneChild) {
+        final int groupPos = mActivity.findGroupWithNumChildren(numChildren, atLeastOneChild);
+        
+        assertTrue("Could not find group to expand", groupPos >= 0);
+        assertFalse("Group is already expanded", mListView.isGroupExpanded(groupPos));
+        mListUtil.arrowScrollToSelectedPosition(groupPos);
+        getInstrumentation().waitForIdleSync();
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();
+        assertTrue("Group did not expand", mListView.isGroupExpanded(groupPos));
+        
+        return groupPos;
+    }
+
+    @MediumTest
+    public void testExpandGroup() {
+        expandGroup(-1, true);
+    }
+    
+    @MediumTest
+    public void testCollapseGroup() {
+        final int groupPos = expandGroup(-1, true);
+        
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();
+        assertFalse("Group did not collapse", mListView.isGroupExpanded(groupPos));
+    }
+    
+    @MediumTest
+    public void testExpandedGroupMovement() {
+
+        // Expand the first group
+        mListUtil.arrowScrollToSelectedPosition(0);
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();
+
+        // Ensure it expanded
+        assertTrue("Group did not expand", mListView.isGroupExpanded(0));
+        
+        // Wait until that's all good
+        getInstrumentation().waitForIdleSync();
+        
+        // Make sure it expanded
+        assertTrue("Group did not expand", mListView.isGroupExpanded(0));
+        
+        // Insert a collapsed group in front of the one just expanded
+        List<MyGroup> groups = mActivity.getGroups();
+        MyGroup insertedGroup = new MyGroup(1);
+        groups.add(0, insertedGroup);
+        
+        // Notify data change
+        assertTrue("Adapter is not an instance of the base adapter",
+                mAdapter instanceof BaseExpandableListAdapter);
+        final BaseExpandableListAdapter adapter = (BaseExpandableListAdapter) mAdapter;
+     
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                adapter.notifyDataSetChanged();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        
+        // Make sure the right group is expanded
+        assertTrue("The expanded state didn't stay with the proper group",
+                mListView.isGroupExpanded(1));
+        assertFalse("The expanded state was given to the inserted group",
+                mListView.isGroupExpanded(0));
+    }
+    
+}
\ No newline at end of file
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java
new file mode 100644
index 0000000..49b5106
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.expandablelistview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ExpandableListView;
+
+import com.android.frameworktest.expandablelistview.ExpandableListWithHeaders;
+import com.android.frameworktest.util.ListUtil;
+
+public class ExpandableListWithHeadersTest extends ActivityInstrumentationTestCase<ExpandableListWithHeaders> {
+    private ExpandableListView mExpandableListView;
+    private ListUtil mListUtil;
+    
+    public ExpandableListWithHeadersTest() {
+        super("com.android.frameworktest",
+                ExpandableListWithHeaders.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        mExpandableListView = getActivity().getExpandableListView();
+        mListUtil = new ListUtil(mExpandableListView, getInstrumentation());
+    }
+    
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mExpandableListView);
+    }
+    
+    @MediumTest
+    public void testExpandOnFirstPosition() {
+        // Should be a header, and hence the first group should NOT have expanded
+        mListUtil.arrowScrollToSelectedPosition(0);
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();
+        assertFalse(mExpandableListView.isGroupExpanded(0));
+    }
+
+    @LargeTest
+    public void testExpandOnFirstGroup() {
+        mListUtil.arrowScrollToSelectedPosition(getActivity().getNumOfHeadersAndFooters());
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();
+        assertTrue(mExpandableListView.isGroupExpanded(0));
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/DescendantFocusabilityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/DescendantFocusabilityTest.java
new file mode 100644
index 0000000..6bdd416
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/DescendantFocusabilityTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.focus;
+
+import com.android.frameworktest.focus.DescendantFocusability;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.UiThreadTest;
+import android.test.TouchUtils;
+import android.view.ViewGroup;
+
+public class DescendantFocusabilityTest extends ActivityInstrumentationTestCase<DescendantFocusability> {
+
+    private DescendantFocusability a;
+
+    public DescendantFocusabilityTest() {
+        super("com.android.frameworktest", DescendantFocusability.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        a = getActivity();
+
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertEquals(ViewGroup.FOCUS_BEFORE_DESCENDANTS,
+            a.beforeDescendants.getDescendantFocusability());
+        assertEquals(ViewGroup.FOCUS_AFTER_DESCENDANTS,
+            a.afterDescendants.getDescendantFocusability());
+        assertEquals(ViewGroup.FOCUS_BLOCK_DESCENDANTS,
+            a.blocksDescendants.getDescendantFocusability());
+
+        assertTrue(a.beforeDescendantsChild.isFocusable());
+        assertTrue(a.afterDescendantsChild.isFocusable());
+        assertTrue(a.blocksDescendantsChild.isFocusable());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testBeforeDescendants() {
+        a.beforeDescendants.setFocusable(true);
+
+        assertTrue(a.beforeDescendants.requestFocus());
+        assertTrue(a.beforeDescendants.isFocused());
+
+        a.beforeDescendants.setFocusable(false);
+        a.beforeDescendants.requestFocus();
+        assertTrue(a.beforeDescendantsChild.isFocused());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testAfterDescendants() {
+        a.afterDescendants.setFocusable(true);
+
+        assertTrue(a.afterDescendants.requestFocus());
+        assertTrue(a.afterDescendantsChild.isFocused());
+
+        a.afterDescendants.setFocusable(false);
+        assertTrue(a.afterDescendants.requestFocus());
+        assertTrue(a.afterDescendantsChild.isFocused());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testBlocksDescendants() {
+        a.blocksDescendants.setFocusable(true);
+        assertTrue(a.blocksDescendants.requestFocus());
+        assertTrue(a.blocksDescendants.isFocused());
+        assertFalse(a.blocksDescendantsChild.isFocused());
+
+        a.blocksDescendants.setFocusable(false);
+        assertFalse(a.blocksDescendants.requestFocus());
+        assertFalse(a.blocksDescendants.isFocused());
+        assertFalse(a.blocksDescendantsChild.isFocused());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testChildOfDescendantBlockerRequestFocusFails() {
+        assertFalse(a.blocksDescendantsChild.requestFocus());
+    }
+
+    @LargeTest
+    public void testBeforeDescendantsEnterTouchMode() {
+        a.runOnUiThread(new Runnable() {
+            public void run() {
+                a.beforeDescendants.setFocusableInTouchMode(true);
+                a.beforeDescendantsChild.requestFocus();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertTrue(a.beforeDescendantsChild.isFocused());
+        assertFalse(a.beforeDescendantsChild.isInTouchMode());
+
+        TouchUtils.clickView(this, a.beforeDescendantsChild);
+        assertTrue(a.beforeDescendantsChild.isInTouchMode());
+        assertFalse(a.beforeDescendants.isFocused());        
+    }
+
+    @LargeTest
+    public void testAfterDescendantsEnterTouchMode() {
+        a.runOnUiThread(new Runnable() {
+            public void run() {
+                a.afterDescendants.setFocusableInTouchMode(true);
+                a.afterDescendantsChild.requestFocus();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertTrue(a.afterDescendantsChild.isFocused());
+        assertFalse(a.afterDescendantsChild.isInTouchMode());
+
+        TouchUtils.clickView(this, a.afterDescendantsChild);
+        assertTrue(a.afterDescendantsChild.isInTouchMode());
+        assertTrue(a.afterDescendants.isFocused());
+    }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusAfterRemovalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusAfterRemovalTest.java
new file mode 100644
index 0000000..8fb9b01
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusAfterRemovalTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.focus.FocusAfterRemoval;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * {@link FocusAfterRemoval} is set up to exercise cases where the views that
+ * have focus become invisible or GONE.
+ */
+public class FocusAfterRemovalTest extends ActivityInstrumentationTestCase<FocusAfterRemoval> {
+
+    private LinearLayout mLeftLayout;
+    private Button mTopLeftButton;
+    private Button mBottomLeftButton;
+    private Button mTopRightButton;
+    private Button mBottomRightButton;
+
+    public FocusAfterRemovalTest() {
+        super("com.android.frameworktest", FocusAfterRemoval.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final FocusAfterRemoval a = getActivity();
+        mLeftLayout = (LinearLayout) a.findViewById(R.id.leftLayout);
+        mTopLeftButton = (Button) a.findViewById(R.id.topLeftButton);
+        mBottomLeftButton = (Button) a.findViewById(R.id.bottomLeftButton);
+        mTopRightButton = (Button) a.findViewById(R.id.topRightButton);
+        mBottomRightButton = (Button) a.findViewById(R.id.bottomRightButton);
+    }
+
+    // Test that setUp did what we expect it to do.  These asserts
+    // can't go in SetUp, or the test will hang.
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mLeftLayout);
+        assertNotNull(mTopLeftButton);
+        assertNotNull(mTopRightButton);
+        assertNotNull(mBottomLeftButton);
+        assertNotNull(mBottomRightButton);
+
+        assertTrue(mTopLeftButton.hasFocus());
+    }
+
+    // if a parent layout becomes GONE when one of its children has focus,
+    // make sure the focus moves to something visible (bug 827087)
+    @MediumTest
+    public void testFocusLeavesWhenParentLayoutIsGone() throws Exception {
+
+        // clicking on this button makes its parent linear layout GONE
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        assertEquals(View.GONE, mLeftLayout.getVisibility());
+
+        assertTrue("focus should jump to visible button",
+                mTopRightButton.hasFocus());
+
+    }
+
+    @MediumTest
+    public void testFocusLeavesWhenParentLayoutInvisible() throws Exception {
+
+        // move down to bottom left button
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue(mBottomLeftButton.hasFocus());
+
+        // clicking on this button makes its parent linear layout INVISIBLE
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        assertEquals(View.INVISIBLE,
+                getActivity().findViewById(R.id.leftLayout).getVisibility());
+
+        assertTrue("focus should jump to visible button",
+                mTopRightButton.hasFocus());
+    }
+
+    @MediumTest
+    public void testFocusLeavesWhenFocusedViewBecomesGone() throws Exception {
+
+        // move to top right
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        assertTrue(mTopRightButton.hasFocus());
+
+        // click making it GONE
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        assertEquals(View.GONE, mTopRightButton.getVisibility());
+
+        assertTrue("focus should jump to visible button",
+                mTopLeftButton.hasFocus());
+    }
+
+    @MediumTest
+    public void testFocusLeavesWhenFocusedViewBecomesInvisible() throws Exception {
+
+        // move to bottom right
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue(mBottomRightButton.hasFocus());
+
+        // click making it INVISIBLE
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        assertEquals(View.INVISIBLE, mBottomRightButton.getVisibility());
+
+        assertTrue("focus should jump to visible button",
+                mTopLeftButton.hasFocus());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusChangeWithInterestingRectHintTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusChangeWithInterestingRectHintTest.java
new file mode 100644
index 0000000..6bdb1ca
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusChangeWithInterestingRectHintTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.focus.AdjacentVerticalRectLists;
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+/**
+ * {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
+ * and
+ * {@link android.view.View#requestFocus(int, android.graphics.Rect)}
+ * work together to give a newly focused item a hint about the most interesting
+ * rectangle of the previously focused view.  The view taking focus can use this
+ * to set an internal selection more appropriate using this rect.
+ *
+ * This tests that behavior using three adjacent {@link com.android.frameworktest.util.InternalSelectionView}
+ * that report interesting rects when giving up focus, and use interesting rects
+ * when taking focus to best select the internal row to show as selected.
+ *
+ */
+public class FocusChangeWithInterestingRectHintTest extends ActivityInstrumentationTestCase<AdjacentVerticalRectLists> {
+
+    private InternalSelectionView mLeftColumn;
+    private InternalSelectionView mMiddleColumn;
+    private InternalSelectionView mRightColumn;
+
+    public FocusChangeWithInterestingRectHintTest() {
+        super("com.android.frameworktest", AdjacentVerticalRectLists.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mLeftColumn = getActivity().getLeftColumn();
+        mMiddleColumn = getActivity().getMiddleColumn();
+        mRightColumn = getActivity().getRightColumn();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mLeftColumn);
+        assertNotNull(mMiddleColumn);
+        assertNotNull(mRightColumn);
+        assertTrue(mLeftColumn.hasFocus());
+        assertTrue("need at least 3 rows", mLeftColumn.getNumRows() > 2);
+        assertEquals(mLeftColumn.getNumRows(), mMiddleColumn.getNumRows());
+        assertEquals(mMiddleColumn.getNumRows(), mRightColumn.getNumRows());
+    }
+
+
+    @LargeTest
+    public void testSnakeBackAndForth() {
+        final int numRows = mLeftColumn.getNumRows();
+        for (int row = 0; row < numRows; row++) {
+
+            if ((row % 2) == 0) {
+                assertEquals("row " + row + ": should be at left column",
+                        row, mLeftColumn.getSelectedRow());
+
+                sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+                assertTrue("row " + row + ": should be at middle column",
+                        mMiddleColumn.hasFocus());
+                assertEquals(row, mMiddleColumn.getSelectedRow());
+
+                sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+                assertTrue("row " + row + ": should be at right column",
+                        mRightColumn.hasFocus());
+                assertEquals(row, mRightColumn.getSelectedRow());
+
+                if (row < numRows - 1) {
+                    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+                    assertEquals(row + 1, mRightColumn.getSelectedRow());
+                }
+            } else {
+                assertTrue("row " + row + ": should be at right column",
+                        mRightColumn.hasFocus());
+
+                sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+                assertTrue("row " + row + ": should be at middle column",
+                        mMiddleColumn.hasFocus());
+                assertEquals(row, mMiddleColumn.getSelectedRow());
+
+                sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+                assertEquals("row " + row + ": should be at left column",
+                        row, mLeftColumn.getSelectedRow());
+
+                if (row < numRows - 1) {
+                    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+                    assertEquals(row + 1, mLeftColumn.getSelectedRow());
+                }
+           }
+        }
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/GoneParentFocusedChildTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/GoneParentFocusedChildTest.java
new file mode 100644
index 0000000..a490322
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/GoneParentFocusedChildTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import com.android.frameworktest.focus.GoneParentFocusedChild;
+
+/**
+ * When a parent is GONE, key events shouldn't go to its children, even if they
+ * have focus. (part of investigation into issue 945150).
+ */
+public class GoneParentFocusedChildTest
+        extends ActivityInstrumentationTestCase<GoneParentFocusedChild> {
+
+
+    public GoneParentFocusedChildTest() {
+        super("com.android.frameworktest", GoneParentFocusedChild.class);
+    }
+
+    @MediumTest
+    public void testPreconditinos() {
+        assertNotNull(getActivity().getLayout());
+        assertNotNull(getActivity().getGoneGroup());
+        assertNotNull(getActivity().getButton());
+        assertTrue("button should have focus",
+                getActivity().getButton().hasFocus());
+        assertEquals("gone group should be, well, gone!",
+                View.GONE,
+                getActivity().getGoneGroup().getVisibility());
+        assertFalse("the activity should have received no key events",
+                getActivity().isUnhandledKeyEvent());
+    }
+
+    @MediumTest
+    public void testKeyEventGoesToActivity() {
+        sendKeys(KeyEvent.KEYCODE_J);
+        assertTrue(getActivity().isUnhandledKeyEvent());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/HorizontalFocusSearchTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/HorizontalFocusSearchTest.java
new file mode 100644
index 0000000..ca7cd7e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/HorizontalFocusSearchTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.focus.HorizontalFocusSearch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.view.View;
+
+import static com.android.frameworktest.focus.VerticalFocusSearchTest.FocusSearchAlg;
+import static com.android.frameworktest.focus.VerticalFocusSearchTest.NewFocusSearchAlg;
+
+/**
+ * Tests that focus searching works on a horizontal linear layout of buttons of
+ * various widths and vertical placements.
+ */
+// Suppress until bug http://b/issue?id=1416545 is fixed.
+@Suppress
+public class HorizontalFocusSearchTest extends ActivityInstrumentationTestCase<HorizontalFocusSearch> {
+
+    private FocusSearchAlg mFocusFinder;
+
+    private LinearLayout mLayout;
+    private Button mLeftTall;
+    private Button mMidShort1Top;
+    private Button mMidShort2Bottom;
+    private Button mRightTall;
+
+
+    public HorizontalFocusSearchTest() {
+        super("com.android.frameworktest", HorizontalFocusSearch.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mFocusFinder = new NewFocusSearchAlg();
+
+        mLayout = getActivity().getLayout();
+        mLeftTall = getActivity().getLeftTall();
+        mMidShort1Top = getActivity().getMidShort1Top();
+        mMidShort2Bottom = getActivity().getMidShort2Bottom();
+        mRightTall = getActivity().getRightTall();
+    }
+
+    public void testPreconditions() {
+        assertNotNull(mLayout);
+        assertNotNull(mLeftTall);
+        assertNotNull(mMidShort1Top);
+        assertNotNull(mMidShort2Bottom);
+        assertNotNull(mRightTall);
+    }
+
+    public void testSearchFromLeftButton() {
+        assertNull("going up from mLeftTall",
+                mFocusFinder.findNextFocus(mLayout, mLeftTall, View.FOCUS_UP));
+        assertNull("going down from mLeftTall",
+                mFocusFinder.findNextFocus(mLayout, mLeftTall, View.FOCUS_DOWN));
+        assertNull("going left from mLeftTall",
+                mFocusFinder.findNextFocus(mLayout, mLeftTall, View.FOCUS_LEFT));
+
+        assertEquals("going right from mLeftTall",
+                mMidShort1Top,
+                mFocusFinder.findNextFocus(mLayout, mLeftTall, View.FOCUS_RIGHT));
+    }
+
+    public void TODO_testSearchFromMiddleLeftButton() {
+        assertNull("going up from mMidShort1Top",
+                mFocusFinder.findNextFocus(mLayout, mMidShort1Top, View.FOCUS_UP));
+        assertEquals("going down from mMidShort1Top",
+                mMidShort2Bottom,
+                mFocusFinder.findNextFocus(mLayout, mMidShort1Top, View.FOCUS_DOWN));
+        assertEquals("going left from mMidShort1Top",
+                mLeftTall,
+                mFocusFinder.findNextFocus(mLayout, mMidShort1Top, View.FOCUS_LEFT));
+        assertEquals("going right from mMidShort1Top",
+                mMidShort2Bottom,
+                mFocusFinder.findNextFocus(mLayout, mMidShort1Top, View.FOCUS_RIGHT));
+    }
+
+    public void TODO_testSearchFromMiddleRightButton() {
+        assertEquals("going up from mMidShort2Bottom",
+                mMidShort1Top,
+                mFocusFinder.findNextFocus(mLayout, mMidShort2Bottom, View.FOCUS_UP));
+        assertNull("going down from mMidShort2Bottom",
+                mFocusFinder.findNextFocus(mLayout, mMidShort2Bottom, View.FOCUS_DOWN));
+        assertEquals("going left from mMidShort2Bottom",
+                mMidShort1Top,
+                mFocusFinder.findNextFocus(mLayout, mMidShort2Bottom, View.FOCUS_LEFT));
+        assertEquals("goind right from mMidShort2Bottom",
+                mRightTall,
+                mFocusFinder.findNextFocus(mLayout, mMidShort2Bottom, View.FOCUS_RIGHT));
+    }
+
+    public void testSearchFromRightButton() {
+        assertNull("going up from mRightTall",
+                mFocusFinder.findNextFocus(mLayout, mRightTall, View.FOCUS_UP));
+        assertNull("going down from mRightTall",
+                mFocusFinder.findNextFocus(mLayout, mRightTall, View.FOCUS_DOWN));
+        assertEquals("going left from mRightTall",
+                mMidShort2Bottom,
+                mFocusFinder.findNextFocus(mLayout, mRightTall, View.FOCUS_LEFT));
+        assertNull("going right from mRightTall",
+                mFocusFinder.findNextFocus(mLayout, mRightTall, View.FOCUS_RIGHT));
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/LinearLayoutGridTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/LinearLayoutGridTest.java
new file mode 100644
index 0000000..c26c331
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/LinearLayoutGridTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.test.SingleLaunchActivityTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.FocusFinder;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.frameworktest.focus.LinearLayoutGrid;
+
+/**
+ * Tests focus searching between buttons within a grid that are touching, for example,
+ * two buttons next two each other would have the left button's right equal to the
+ * right button's left.  Same goes for top and bottom edges.
+ *
+ * This exercises some edge cases of {@link android.view.FocusFinder}.
+ */
+public class LinearLayoutGridTest extends SingleLaunchActivityTestCase<LinearLayoutGrid> {
+    private ViewGroup mRootView;
+
+    public LinearLayoutGridTest() {
+        super("com.android.frameworktest", LinearLayoutGrid.class);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mRootView = getActivity().getRootView();
+    }
+
+    @MediumTest
+    public void testGoDownFromMiddle() {
+        assertEquals(getActivity().getButtonAt(2, 1),
+                FocusFinder.getInstance().findNextFocus(
+                        mRootView,
+                        getActivity().getButtonAt(1, 1),
+                        View.FOCUS_DOWN));
+    }
+
+    @MediumTest
+    public void testGoUpFromMiddle() {
+        assertEquals(getActivity().getButtonAt(0, 1),
+                FocusFinder.getInstance().findNextFocus(
+                        mRootView,
+                        getActivity().getButtonAt(1, 1),
+                        View.FOCUS_UP));
+    }
+
+    @MediumTest
+    public void testGoRightFromMiddle() {
+        assertEquals(getActivity().getButtonAt(1, 2),
+                FocusFinder.getInstance().findNextFocus(
+                        mRootView,
+                        getActivity().getButtonAt(1, 1),
+                        View.FOCUS_RIGHT));
+    }
+
+    @MediumTest
+    public void testGoLeftFromMiddle() {
+        assertEquals(getActivity().getButtonAt(1, 0),
+                FocusFinder.getInstance().findNextFocus(
+                        mRootView,
+                        getActivity().getButtonAt(1, 1),
+                        View.FOCUS_LEFT));
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListOfButtonsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListOfButtonsTest.java
new file mode 100644
index 0000000..902fc1c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListOfButtonsTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.focus.ListOfButtons;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * Tests that focus works as expected when navigating into and out of
+ * a {@link ListView} that has buttons in it.
+ */
+public class ListOfButtonsTest extends ActivityInstrumentationTestCase<ListOfButtons> {
+
+    private ListAdapter mListAdapter;
+    private Button mButtonAtTop;
+
+    private ListView mListView;
+
+    public ListOfButtonsTest() {
+        super("com.android.frameworktest", ListOfButtons.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        ListOfButtons a = getActivity();
+        mListAdapter = a.getListAdapter();
+        mButtonAtTop = (Button) a.findViewById(R.id.button);
+        mListView = a.getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mListAdapter);
+        assertNotNull(mButtonAtTop);
+        assertNotNull(mListView);
+
+        assertFalse(mButtonAtTop.hasFocus());
+        assertTrue(mListView.hasFocus());
+        assertEquals("expecting 0 index to be selected",
+                0, mListView.getSelectedItemPosition());
+    }
+
+    @MediumTest
+    public void testNavigateToButtonAbove() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+        assertTrue(mButtonAtTop.hasFocus());        
+        assertFalse(mListView.hasFocus());
+    }
+
+    @MediumTest
+    public void testNavigateToSecondItem() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertTrue(mListView.hasFocus());
+
+        View childOne = mListView.getChildAt(1);
+        assertNotNull(childOne);
+        assertEquals(childOne, mListView.getFocusedChild());
+        assertTrue(childOne.hasFocus());
+    }
+
+    @MediumTest
+    public void testNavigateUpAboveAndBackOut() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertFalse("button at top should have focus back",
+                mButtonAtTop.hasFocus());
+        assertTrue(mListView.hasFocus());
+    }
+
+    // TODO: this reproduces bug 981791
+    public void TODO_testNavigateThroughAllButtonsAndBack() {
+
+        String[] labels = getActivity().getLabels();
+        for (int i = 0; i < labels.length; i++) {
+            String label = labels[i];
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            getInstrumentation().waitForIdleSync();
+
+            String indexInfo = "index: " + i + ", label: " + label;
+
+            assertTrue(indexInfo, mListView.hasFocus());
+            
+            Button button = (Button) mListView.getSelectedView();
+            assertNotNull(indexInfo, button);
+            assertEquals(indexInfo, label, button.getText().toString());
+            assertTrue(indexInfo, button.hasFocus());
+        }
+
+        // pressing down again shouldn't matter; make sure last item keeps focus
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+
+        for (int i = labels.length - 1; i >= 0; i--) {
+            String label = labels[i];
+
+            String indexInfo = "index: " + i + ", label: " + label;
+
+            assertTrue(indexInfo, mListView.hasFocus());
+
+            Button button = (Button) mListView.getSelectedView();
+            assertNotNull(indexInfo, button);
+            assertEquals(indexInfo, label, button.getText().toString());
+            assertTrue(indexInfo, button.hasFocus());
+
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+            getInstrumentation().waitForIdleSync();
+        }
+
+        assertTrue("button at top should have focus back",
+                mButtonAtTop.hasFocus());
+        assertFalse(mListView.hasFocus());
+    }
+
+    @MediumTest
+    public void testGoInAndOutOfListWithItemsFocusable() {
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+        assertTrue(mButtonAtTop.hasFocus());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        final String firstButtonLabel = getActivity().getLabels()[0];
+        final Button firstButton = (Button) mListView.getSelectedView();
+
+        assertTrue(firstButton.isFocused());
+        assertEquals(firstButtonLabel, firstButton.getText());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue(mButtonAtTop.isFocused());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue(firstButton.isFocused());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue(mButtonAtTop.isFocused());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue(firstButton.isFocused());
+    }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabelsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabelsTest.java
new file mode 100644
index 0000000..c094882
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabelsTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.focus.ListWithFooterViewAndNewLabels;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+public class ListWithFooterViewAndNewLabelsTest
+        extends ActivityInstrumentationTestCase<ListWithFooterViewAndNewLabels> {
+
+    private Button mButton;
+
+    private ListAdapter mAdapter;
+
+    private ListView mListView;
+
+
+    public ListWithFooterViewAndNewLabelsTest() {
+        super("com.android.frameworktest",
+                ListWithFooterViewAndNewLabels.class);
+    }
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        ListWithFooterViewAndNewLabels a = getActivity();
+        mButton = (Button) a.findViewById(R.id.button);
+        mAdapter = a.getListAdapter();
+        mListView = a.getListView();
+    }
+
+    // bug 900885
+    public void FAILING_testPreconditions() {
+        assertNotNull(mButton);
+        assertNotNull(mAdapter);
+        assertNotNull(mListView);
+
+        assertTrue(mButton.hasFocus());
+        assertEquals("expected list adapter to have 1 item",
+                1, mAdapter.getCount());
+        assertEquals("expected list view to have 2 items (1 in adapter, plus " 
+                + "the footer view).",
+                2, mListView.getCount());
+
+        // fails here!!!
+        assertEquals("Expecting the selected index to be 0, the first non footer "
+                + "view item.",
+                0, mListView.getSelectedItemPosition());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/RequestFocusTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/RequestFocusTest.java
new file mode 100644
index 0000000..5fb3a29
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/RequestFocusTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.focus.RequestFocus;
+import com.android.frameworktest.R;
+
+import android.os.Handler;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.util.AndroidRuntimeException;
+
+/**
+ * {@link RequestFocusTest} is set up to exercise cases where the views that
+ * have focus become invisible or GONE.
+ */
+public class RequestFocusTest extends ActivityInstrumentationTestCase<RequestFocus> {
+
+    private Button mTopLeftButton;
+    private Button mBottomLeftButton;
+    private Button mTopRightButton;
+    private Button mBottomRightButton;
+    private Handler mHandler;
+
+    public RequestFocusTest() {
+        super("com.android.frameworktest", RequestFocus.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final RequestFocus a = getActivity();
+        mHandler = a.getHandler();
+        mTopLeftButton = (Button) a.findViewById(R.id.topLeftButton);
+        mBottomLeftButton = (Button) a.findViewById(R.id.bottomLeftButton);
+        mTopRightButton = (Button) a.findViewById(R.id.topRightButton);
+        mBottomRightButton = (Button) a.findViewById(R.id.bottomRightButton);
+    }
+
+    // Test that setUp did what we expect it to do.  These asserts
+    // can't go in SetUp, or the test will hang.
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mHandler);
+        assertNotNull(mTopLeftButton);
+        assertNotNull(mTopRightButton);
+        assertNotNull(mBottomLeftButton);
+        assertNotNull(mBottomRightButton);
+        assertTrue("requestFocus() should work from onCreate.", mBottomRightButton.hasFocus());
+    }
+
+    // Test that a posted requestFocus works.
+    @LargeTest
+    public void testPostedRequestFocus() throws Exception {
+        mHandler.post(new Runnable() { public void run() {
+            mBottomLeftButton.requestFocus();
+        }});
+        synchronized(this) {
+            try {
+                wait(500);
+            } catch (InterruptedException e) {
+                // Don't care.
+            }
+        }
+        assertTrue("Focus should move to bottom left", mBottomLeftButton.hasFocus());
+    }
+
+    // Test that a requestFocus from the wrong thread fails.
+    @MediumTest
+    public void testWrongThreadRequestFocusFails() throws Exception {
+        try {
+            mTopRightButton.requestFocus();
+            fail("requestFocus from wrong thread should raise exception.");
+        } catch (AndroidRuntimeException e) {
+            // Expected.  The actual exception is not public, so we can't catch it.
+            assertEquals("android.view.ViewRoot$CalledFromWrongThreadException",
+                         e.getClass().getName());
+        }
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java
new file mode 100644
index 0000000..07916ee
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import android.graphics.Rect;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import com.android.frameworktest.focus.ListOfInternalSelectionViews;
+import com.android.frameworktest.util.InternalSelectionView;
+
+
+/**
+ * TODO: extract base test case that launches {@link ListOfInternalSelectionViews} with
+ * bundle params.
+ */
+public class ScrollingThroughListOfFocusablesTest extends InstrumentationTestCase {
+
+    Rect mTempRect = new Rect();
+
+    private ListOfInternalSelectionViews mActivity;
+    private ListView mListView;
+
+    private int mNumItems = 4;
+    private int mNumRowsPerItem = 5;
+    private double mScreenHeightFactor = 5 /4;
+
+    @Override
+    protected void setUp() throws Exception {
+        mActivity = launchActivity(
+                "com.android.frameworktest",
+                ListOfInternalSelectionViews.class,
+                ListOfInternalSelectionViews.getBundleFor(
+                    mNumItems,      // 4 items
+                    mNumRowsPerItem,      // 5 internally selectable rows per item
+                    mScreenHeightFactor)); // each item is 5 / 4 screen height tall
+        mListView = mActivity.getListView();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mActivity.finish();
+        super.tearDown();
+    }
+
+    @MediumTest
+    public void testPreconditions() throws Exception {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        assertEquals(mNumItems, mActivity.getNumItems());
+        assertEquals(mNumRowsPerItem, mActivity.getNumRowsPerItem());
+    }
+
+    @MediumTest
+    public void testScrollingDownInFirstItem() throws Exception {
+
+        for (int i = 0; i < mNumRowsPerItem; i++) {
+            assertEquals(0, mListView.getSelectedItemPosition());
+            InternalSelectionView view = mActivity.getSelectedView();
+
+            assertInternallySelectedRowOnScreen(view, i);
+
+            // move to next row
+            if (i < mNumRowsPerItem - 1) {
+                sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+                getInstrumentation().waitForIdleSync();
+            }
+        }
+
+        {
+            assertEquals(0, mListView.getSelectedItemPosition());
+            InternalSelectionView view = (InternalSelectionView)
+                    mListView.getSelectedView();
+
+            // 1 pixel tolerance in case height / 4 is not an even number
+            final int fadingEdge = mListView.getBottom() - mListView.getVerticalFadingEdgeLength();
+            assertTrue("bottom of view should be just above fading edge",
+                    view.getBottom() >= fadingEdge - 1 &&
+                    view.getBottom() <= fadingEdge);
+        }
+
+
+        // make sure fading edge is the expected view
+        {
+            assertEquals("should be a second view visible due to the fading edge",
+                            2, mListView.getChildCount());
+            InternalSelectionView peekingChild = (InternalSelectionView)
+                    mListView.getChildAt(1);
+            assertNotNull(peekingChild);
+            assertEquals("wrong value for peeking list item",
+                    mActivity.getLabelForPosition(1), peekingChild.getLabel());
+        }
+    }
+
+
+    @MediumTest
+    public void testScrollingToSecondItem() throws Exception {
+
+        for (int i = 0; i < mNumRowsPerItem; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            getInstrumentation().waitForIdleSync();
+        }
+
+        assertEquals("should have moved to second item",
+                1, mListView.getSelectedItemPosition());
+    }
+
+    @LargeTest
+    public void testNoFadingEdgeAtBottomOfLastItem() {
+
+        // move down to last item
+        for (int i = 0; i < mNumItems; i++) {
+            for (int j = 0; j < mNumRowsPerItem; j++) {
+                if (i < mNumItems - 1 || j < mNumRowsPerItem - 1) {
+                    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+                    getInstrumentation().waitForIdleSync();
+                }
+            }
+        }
+
+        assertEquals(mNumItems - 1, mListView.getSelectedItemPosition());
+        InternalSelectionView view = mActivity.getSelectedView();
+        assertEquals(mNumRowsPerItem - 1, view.getSelectedRow());
+
+        view.getRectForRow(mTempRect, mNumRowsPerItem - 1);
+        mListView.offsetDescendantRectToMyCoords(view, mTempRect);
+
+        assertTrue("bottom of last row of last item should be at " +
+                "the bottom of the list view (no fading edge)",
+                mListView.getBottom() - mListView.getVerticalFadingEdgeLength() < mTempRect.bottom);
+    }
+
+    @LargeTest
+    public void testNavigatingUpThroughInternalSelection() throws Exception {
+
+        // get to bottom of second item
+        for (int i = 0; i < 2; i++) {
+            for (int j = 0; j < mNumRowsPerItem; j++) {
+                if (i < 1 || j < mNumRowsPerItem - 1) {
+                    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+                    getInstrumentation().waitForIdleSync();
+                }
+            }
+        }
+
+
+        // (make sure we are at last row of second item)
+        {
+            assertEquals(1, mListView.getSelectedItemPosition());
+            InternalSelectionView view = mActivity.getSelectedView();
+            assertEquals(mNumRowsPerItem - 1, view.getSelectedRow());
+        }
+
+        // go back up to the top of the second item
+        for (int i = mNumRowsPerItem - 1; i >= 0; i--) {
+            assertEquals(1, mListView.getSelectedItemPosition());
+            InternalSelectionView view = mActivity.getSelectedView();
+
+            assertInternallySelectedRowOnScreen(view, i);
+
+            // move up to next row
+            if (i > 0) {
+                sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+                getInstrumentation().waitForIdleSync();
+            }
+        }
+
+        // now we are at top row, should have caused scrolling, and fading edge...
+        {
+            assertEquals(1, mListView.getSelectedItemPosition());
+            InternalSelectionView view = mActivity.getSelectedView();
+            assertEquals(0, view.getSelectedRow());
+
+            view.getDrawingRect(mTempRect);
+            mListView.offsetDescendantRectToMyCoords(view, mTempRect);
+            assertEquals("top of selected row should be just below top vertical fading edge",
+                    mListView.getVerticalFadingEdgeLength(),
+                    view.getTop());
+        }
+
+        // make sure fading edge is the view we expect
+        {
+            final InternalSelectionView view =
+                    (InternalSelectionView) mListView.getChildAt(0);
+            assertEquals(mActivity.getLabelForPosition(0), view.getLabel());
+        }
+
+
+    }
+
+    /**
+     * @param internalFocused The view to check
+     * @param row
+     */
+    private void assertInternallySelectedRowOnScreen(
+            InternalSelectionView internalFocused,
+            int row) {
+        assertEquals("expecting selected row",
+                row, internalFocused.getSelectedRow());
+
+        internalFocused.getRectForRow(mTempRect, row);
+        mListView.offsetDescendantRectToMyCoords(internalFocused, mTempRect);
+
+        assertTrue("top of row " + row + " should be on sreen",
+                mTempRect.top >= 0);
+        assertTrue("bottom of row " + row + " should be on sreen",
+                mTempRect.bottom < mActivity.getScreenHeight());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/VerticalFocusSearchTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/VerticalFocusSearchTest.java
new file mode 100644
index 0000000..47a81fb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/VerticalFocusSearchTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.focus;
+
+import com.android.frameworktest.focus.VerticalFocusSearch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.view.FocusFinder;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+/**
+ * Tests that focus searching works on a vertical linear layout of buttons of
+ * various widths and horizontal placements.
+ */
+// Suppress until bug http://b/issue?id=1416545 is fixed
+@Suppress 
+public class VerticalFocusSearchTest extends ActivityInstrumentationTestCase<VerticalFocusSearch> {
+
+    private LinearLayout mLayout;
+
+    private Button mTopWide;
+    private Button mMidSkinny1Left;
+    private Button mMidSkinny2Right;
+    private Button mBottomWide;
+
+    private FocusSearchAlg mFocusFinder;
+
+    // helps test old and new impls when figuring out why something that used
+    // to work doesn't anymore (or verifying that new works as well as old).
+    interface FocusSearchAlg {
+        View findNextFocus(ViewGroup root, View focused, int direction);
+    }
+
+    // calls new impl
+    static class NewFocusSearchAlg implements FocusSearchAlg {
+
+        public View findNextFocus(ViewGroup root, View focused, int direction) {
+            return FocusFinder.getInstance()
+                    .findNextFocus(root, focused, direction);
+        }
+    }
+
+    public VerticalFocusSearchTest() {
+        super("com.android.frameworktest", VerticalFocusSearch.class);
+    }
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mLayout = getActivity().getLayout();
+        mTopWide = getActivity().getTopWide();
+        mMidSkinny1Left = getActivity().getMidSkinny1Left();
+        mMidSkinny2Right = getActivity().getMidSkinny2Right();
+        mBottomWide = getActivity().getBottomWide();
+
+        mFocusFinder = new NewFocusSearchAlg();
+    }
+
+    public void testPreconditions() {
+        assertNotNull(mLayout);
+        assertNotNull(mTopWide);
+        assertNotNull(mMidSkinny1Left);
+        assertNotNull(mMidSkinny2Right);
+        assertNotNull(mBottomWide);
+    }
+
+    public void testSearchFromTopButton() {
+        assertNull("going up from mTopWide.",
+                mFocusFinder.findNextFocus(mLayout, mTopWide, View.FOCUS_UP));
+
+        assertNull("going left from mTopWide.",
+                mFocusFinder.findNextFocus(mLayout, mTopWide, View.FOCUS_LEFT));
+
+        assertNull("going right from mTopWide.",
+                mFocusFinder.findNextFocus(mLayout, mTopWide, View.FOCUS_RIGHT));
+
+        assertEquals("going down from mTopWide.",
+                mMidSkinny1Left,
+                mFocusFinder
+                .findNextFocus(mLayout, mTopWide, View.FOCUS_DOWN));
+    }
+
+    public void testSearchFromMidLeft() {
+        assertNull("going left should have no next focus",
+                mFocusFinder.findNextFocus(mLayout, mMidSkinny1Left, View.FOCUS_LEFT));
+
+        assertEquals("going right from mMidSkinny1Left should go to mMidSkinny2Right",
+                mMidSkinny2Right,
+                mFocusFinder.findNextFocus(mLayout, mMidSkinny1Left, View.FOCUS_RIGHT));
+
+        assertEquals("going up from mMidSkinny1Left should go to mTopWide",
+                mTopWide,
+                mFocusFinder.findNextFocus(mLayout, mMidSkinny1Left, View.FOCUS_UP));
+
+        assertEquals("going down from mMidSkinny1Left should go to mMidSkinny2Right",
+                mMidSkinny2Right,
+                mFocusFinder.findNextFocus(mLayout, mMidSkinny1Left, View.FOCUS_DOWN));
+    }
+
+    public void testSearchFromMidRight() {
+        assertEquals("going left from mMidSkinny2Right should go to mMidSkinny1Left",
+                mMidSkinny1Left,
+                mFocusFinder.findNextFocus(mLayout, mMidSkinny2Right, View.FOCUS_LEFT));
+
+        assertNull("going right should have no next focus",
+                mFocusFinder.findNextFocus(mLayout, mMidSkinny2Right, View.FOCUS_RIGHT));
+
+        assertEquals("going up from mMidSkinny2Right should go to mMidSkinny1Left",
+                mMidSkinny1Left,
+                mFocusFinder.findNextFocus(mLayout, mMidSkinny2Right, View.FOCUS_UP));
+        
+        assertEquals("going down from mMidSkinny2Right should go to mBottomWide",
+                mBottomWide,
+                mFocusFinder.findNextFocus(mLayout, mMidSkinny2Right, View.FOCUS_DOWN));
+
+    }
+
+    public void testSearchFromFromBottom() {
+        assertNull("going down from bottom button should have no next focus.",
+                mFocusFinder.findNextFocus(mLayout, mBottomWide, View.FOCUS_DOWN));
+
+        assertNull("going left from bottom button should have no next focus.",
+                mFocusFinder.findNextFocus(mLayout, mBottomWide, View.FOCUS_LEFT));
+
+        assertNull("going right from bottom button should have no next focus.",
+                mFocusFinder.findNextFocus(mLayout, mBottomWide, View.FOCUS_RIGHT));
+
+        assertEquals("going up from bottom button should go to mMidSkinny2Right.",
+                mMidSkinny2Right,
+                mFocusFinder.findNextFocus(mLayout, mBottomWide, View.FOCUS_UP));
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInHorizontalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInHorizontalTest.java
new file mode 100644
index 0000000..8af6214
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInHorizontalTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridInHorizontal;
+
+public class GridInHorizontalTest extends ActivityInstrumentationTestCase<GridInHorizontal> {
+
+    private GridInHorizontal mActivity;
+    private GridView mGridView;
+    
+    public GridInHorizontalTest() {
+        super("com.android.frameworktest", GridInHorizontal.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+        assertTrue("Grid has 0 width", mGridView.getMeasuredWidth() > 0);
+        assertTrue("Grid has 0 height", mGridView.getMeasuredHeight() > 0);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInVerticalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInVerticalTest.java
new file mode 100644
index 0000000..61e1c8b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInVerticalTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridInVertical;
+
+public class GridInVerticalTest extends ActivityInstrumentationTestCase<GridInVertical> {
+
+    private GridInVertical mActivity;
+    private GridView mGridView;
+    
+    public GridInVerticalTest() {
+        super("com.android.frameworktest", GridInVertical.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+        assertTrue("Grid has 0 width", mGridView.getMeasuredWidth() > 0);
+        assertTrue("Grid has 0 height", mGridView.getMeasuredHeight() > 0);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridPaddingTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridPaddingTest.java
new file mode 100644
index 0000000..43581c6
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridPaddingTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+public class GridPaddingTest extends ActivityInstrumentationTestCase2<GridPadding> {
+    private GridView mGridView;
+
+    public GridPaddingTest() {
+        super("com.android.frameworktest", GridPadding.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        setActivityInitialTouchMode(true);
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mGridView);
+        assertTrue("Not in touch mode", mGridView.isInTouchMode());
+    }
+
+    @MediumTest
+    public void testResurrectSelection() {
+        sendKeys("DPAD_DOWN");
+        assertEquals("The first item should be selected", mGridView.getSelectedItemPosition(), 0);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridScrollListenerTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridScrollListenerTest.java
new file mode 100644
index 0000000..f939f16
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridScrollListenerTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.KeyEvent;
+import android.widget.AbsListView;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridScrollListener;
+
+public class GridScrollListenerTest extends ActivityInstrumentationTestCase<GridScrollListener> implements
+        AbsListView.OnScrollListener {
+    private GridScrollListener mActivity;
+    private GridView mGridView;
+    private int mFirstVisibleItem = -1;
+    private int mVisibleItemCount = -1;
+    private int mTotalItemCount = -1;
+
+    public GridScrollListenerTest() {
+        super("com.android.frameworktest", GridScrollListener.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+        mGridView.setOnScrollListener(this);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+        
+        assertEquals(0, mFirstVisibleItem);
+    }
+    
+    @LargeTest
+    public void testKeyScrolling() {
+        Instrumentation inst = getInstrumentation();
+        
+        int firstVisibleItem = mFirstVisibleItem;
+        for (int i = 0; i < mVisibleItemCount * 2; i++) {
+            inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        inst.waitForIdleSync();
+        
+        assertTrue("Arrow scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+        
+        firstVisibleItem = mFirstVisibleItem;
+        inst.sendCharacterSync(KeyEvent.KEYCODE_SPACE);
+        inst.waitForIdleSync();
+        
+        assertTrue("Page scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+        
+        firstVisibleItem = mFirstVisibleItem;
+        KeyEvent down = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, 
+                KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON);
+        KeyEvent up = new KeyEvent(0, 0, KeyEvent.ACTION_UP, 
+                KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON);
+        inst.sendKeySync(down);
+        inst.sendKeySync(up);
+        inst.waitForIdleSync();
+        
+        assertTrue("Full scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+        assertEquals("Full scroll did not happen", mTotalItemCount, 
+                mFirstVisibleItem + mVisibleItemCount);    
+    }
+
+    @LargeTest
+    public void testTouchScrolling() {
+        Instrumentation inst = getInstrumentation();
+        
+        int firstVisibleItem = mFirstVisibleItem;
+        TouchUtils.dragQuarterScreenUp(this);
+        TouchUtils.dragQuarterScreenUp(this);
+        assertTrue("Touch scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+    }
+
+    
+    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+        mFirstVisibleItem = firstVisibleItem;
+        mVisibleItemCount = visibleItemCount;
+        mTotalItemCount = totalItemCount;
+    }
+
+    public void onScrollStateChanged(AbsListView view, int scrollState) {
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionBaseTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionBaseTest.java
new file mode 100644
index 0000000..3ca9b09
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionBaseTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.widget.GridView;
+
+public class GridSetSelectionBaseTest<T extends GridScenario> extends ActivityInstrumentationTestCase<T> {
+    private T mActivity;
+    private GridView mGridView;
+
+    protected GridSetSelectionBaseTest(Class<T> klass) {
+        super("com.android.frameworktest", klass);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+
+        // First item should be selected
+        if (mGridView.isStackFromBottom()) {
+            assertEquals(mGridView.getAdapter().getCount() - 1,
+                    mGridView.getSelectedItemPosition());
+        } else {
+            assertEquals(0, mGridView.getSelectedItemPosition());
+        }
+    }
+
+    @MediumTest
+    public void testSetSelectionToTheEnd() {
+        final int target = mGridView.getAdapter().getCount() - 1;
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mGridView.setSelection(target);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        assertEquals(mGridView.getSelectedItemPosition(), target);
+        assertNotNull(mGridView.getSelectedView());
+
+        ViewAsserts.assertOnScreen(mGridView, mGridView.getSelectedView());
+    }
+
+    @MediumTest
+    public void testSetSelectionToMiddle() {
+        final int target = mGridView.getAdapter().getCount() / 2;
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mGridView.setSelection(target);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        assertEquals(mGridView.getSelectedItemPosition(), target);
+        assertNotNull(mGridView.getSelectedView());
+
+        ViewAsserts.assertOnScreen(mGridView, mGridView.getSelectedView());
+    }
+    
+    @MediumTest
+    public void testSetSelectionToTheTop() {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mGridView.setSelection(0);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        assertEquals(mGridView.getSelectedItemPosition(), 0);
+        assertNotNull(mGridView.getSelectedView());
+
+        ViewAsserts.assertOnScreen(mGridView, mGridView.getSelectedView());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionManyTest.java
new file mode 100644
index 0000000..aadc185
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionManyTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridSetSelectionMany;
+
+public class GridSetSelectionManyTest extends GridSetSelectionBaseTest<GridSetSelectionMany> {
+    public GridSetSelectionManyTest() {
+        super(GridSetSelectionMany.class);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomManyTest.java
new file mode 100644
index 0000000..831ba85
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomManyTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridSetSelectionStackFromBottomMany;
+
+public class GridSetSelectionStackFromBottomManyTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottomMany> {
+    public GridSetSelectionStackFromBottomManyTest() {
+        super(GridSetSelectionStackFromBottomMany.class);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomTest.java
new file mode 100644
index 0000000..c4d0513
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridSetSelectionStackFromBottom;
+
+public class GridSetSelectionStackFromBottomTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottom> {
+    public GridSetSelectionStackFromBottomTest() {
+        super(GridSetSelectionStackFromBottom.class);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionTest.java
new file mode 100644
index 0000000..5a584a5
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridSetSelection;
+
+public class GridSetSelectionTest extends GridSetSelectionBaseTest<GridSetSelection> {
+    public GridSetSelectionTest() {
+        super(GridSetSelection.class);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSingleColumnTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSingleColumnTest.java
new file mode 100644
index 0000000..b72a2e0
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSingleColumnTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridSingleColumn;
+
+public class GridSingleColumnTest extends ActivityInstrumentationTestCase<GridSingleColumn> {
+    private GridSingleColumn mActivity;
+    private GridView mGridView;
+
+    public GridSingleColumnTest() {
+        super("com.android.frameworktest", GridSingleColumn.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+        assertEquals(0, mGridView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomManyTest.java
new file mode 100644
index 0000000..a0b819e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomManyTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridStackFromBottomMany;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+import android.test.ActivityInstrumentationTestCase;
+
+public class GridStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
+    private GridStackFromBottomMany mActivity;
+    private GridView mGridView;
+
+    public GridStackFromBottomManyTest() {
+        super("com.android.frameworktest", GridStackFromBottomMany.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+
+        // Last item should be selected
+        assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomTest.java
new file mode 100644
index 0000000..821c7a5
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridStackFromBottom;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+public class GridStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
+    private GridStackFromBottom mActivity;
+    private GridView mGridView;
+
+    public GridStackFromBottomTest() {
+        super("com.android.frameworktest", GridStackFromBottom.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+
+        // Last item should be selected
+        assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchSetSelectionTest.java
new file mode 100644
index 0000000..926d662
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchSetSelectionTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridSimple;
+
+/**
+ * Tests setting the selection in touch mode
+ */
+public class GridTouchSetSelectionTest extends ActivityInstrumentationTestCase<GridSimple> {
+    private GridSimple mActivity;
+    private GridView mGridView;
+
+    public GridTouchSetSelectionTest() {
+        super("com.android.frameworktest", GridSimple.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+    }
+    
+    @LargeTest
+    public void testSetSelection() {
+        TouchUtils.dragQuarterScreenDown(this);
+        TouchUtils.dragQuarterScreenUp(this);
+        
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mGridView.getSelectedItemPosition());
+        
+        final int targetPosition = mGridView.getAdapter().getCount() / 2;
+        
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mGridView.setSelection(targetPosition);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        
+        boolean found = false;
+        int childCount = mGridView.getChildCount();
+        for (int i=0; i<childCount; i++) {
+            View child = mGridView.getChildAt(i);
+            if (child.getId() == targetPosition) {
+                found = true;
+                break;
+            }
+        }
+        assertTrue("Selected item not visible in list", found);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomManyTest.java
new file mode 100644
index 0000000..710617e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomManyTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview.touch;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import com.android.frameworktest.gridview.GridStackFromBottomMany;
+
+import android.widget.GridView;
+import android.view.View;
+import android.test.ActivityInstrumentationTestCase;
+
+public class GridTouchStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
+    private GridStackFromBottomMany mActivity;
+    private GridView mGridView;
+
+    public GridTouchStackFromBottomManyTest() {
+        super("com.android.frameworktest", GridStackFromBottomMany.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+
+        // Last item should be selected
+        assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+    }
+
+    @LargeTest
+    public void testScrollToTop() {
+        View firstChild;
+        TouchUtils.scrollToTop(this, mGridView);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1,
+                mGridView.getSelectedItemPosition());
+
+        firstChild = mGridView.getChildAt(0);
+
+        assertEquals("Item zero not the first child in the grid", 0, firstChild.getId());
+
+        assertEquals("Item zero not at the top of the grid",
+                mGridView.getListPaddingTop(), firstChild.getTop());
+    }
+
+    @MediumTest
+    public void testScrollToBottom() {
+        TouchUtils.scrollToBottom(this, mGridView);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1,
+                mGridView.getSelectedItemPosition());
+
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+        assertEquals("Grid is not scrolled to the bottom", mGridView.getAdapter().getCount() - 1,
+                lastChild.getId());
+
+        assertEquals("Last item is not touching the bottom edge",
+                mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomTest.java
new file mode 100644
index 0000000..e085105
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview.touch;
+
+import com.android.frameworktest.gridview.GridStackFromBottom;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.widget.GridView;
+import android.view.View;
+
+public class GridTouchStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
+    private GridStackFromBottom mActivity;
+    private GridView mGridView;
+
+    public GridTouchStackFromBottomTest() {
+        super("com.android.frameworktest", GridStackFromBottom.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+
+        // First item should be selected
+        assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+    }
+
+    @MediumTest
+    public void testPushUp() {
+        TouchUtils.scrollToBottom(this, mGridView);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1,
+                mGridView.getSelectedItemPosition());
+
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+        assertEquals("Last item not the last child in the grid",
+                mGridView.getAdapter().getCount() - 1, lastChild.getId());
+
+        assertEquals("Last item not at the bottom of the grid",
+                mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+    }
+
+    @MediumTest
+    public void testPullDown() {
+        TouchUtils.scrollToTop(this, mGridView);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1,
+                mGridView.getSelectedItemPosition());
+
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+        assertEquals("Last item not the last child in the grid",
+                mGridView.getAdapter().getCount() - 1, lastChild.getId());
+
+        assertEquals("Last item not at the bottom of the grid",
+                mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+    }
+    
+    @MediumTest
+    public void testPushUpFast() {
+        TouchUtils.dragViewToTop(this, mGridView.getChildAt(mGridView.getChildCount() - 1), 2);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1,
+                mGridView.getSelectedItemPosition());
+
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+        assertEquals("Last item not the last child in the grid",
+                mGridView.getAdapter().getCount() - 1, lastChild.getId());
+
+        assertEquals("Last item not at the bottom of the grid",
+                mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+    }
+
+    @MediumTest
+    public void testPullDownFast() {
+        TouchUtils.dragViewToBottom(this, mGridView.getChildAt(0), 2);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1,
+                mGridView.getSelectedItemPosition());
+
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+        assertEquals("Last item not the last child in the grid",
+                mGridView.getAdapter().getCount() - 1, lastChild.getId());
+
+        assertEquals("Last item not at the bottom of the grid",
+                mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
new file mode 100644
index 0000000..3937c43
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridVerticalSpacingStackFromBottom;
+
+public class GridTouchVerticalSpacingStackFromBottomTest extends ActivityInstrumentationTestCase<GridVerticalSpacingStackFromBottom> {
+    private GridVerticalSpacingStackFromBottom mActivity;
+    private GridView mGridView;
+
+    public GridTouchVerticalSpacingStackFromBottomTest() {
+        super("com.android.frameworktest", GridVerticalSpacingStackFromBottom.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+
+        // Last item should be selected
+        assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+
+    }
+
+    @MediumTest
+    public void testNoScroll() {
+        View firstChild = mGridView.getChildAt(0);
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        
+        int lastTop = lastChild.getTop();
+        
+        TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
+                ViewConfiguration.getTouchSlop());
+        
+        View newLastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        
+        assertEquals("View scrolled too early", lastTop, newLastChild.getTop());
+        assertEquals("Wrong view in last position", mGridView.getAdapter().getCount() - 1, 
+                newLastChild.getId());
+    }
+    
+    @LargeTest
+    public void testShortScroll() {
+        View firstChild = mGridView.getChildAt(0);
+        if (firstChild.getTop() < this.mGridView.getListPaddingTop()) {
+            firstChild = mGridView.getChildAt(1);
+        }
+            
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        
+        int lastTop = lastChild.getTop();
+        
+        TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
+                ViewConfiguration.getTouchSlop() + 1 + 10);
+        
+        View newLastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        
+        assertEquals("View scrolled to wrong position", lastTop, newLastChild.getTop() - 10);
+        assertEquals("Wrong view in last position", mGridView.getAdapter().getCount() - 1,
+                newLastChild.getId());
+    }
+    
+    @LargeTest
+    public void testLongScroll() {
+        View firstChild = mGridView.getChildAt(0);
+        if (firstChild.getTop() < mGridView.getListPaddingTop()) {
+            firstChild = mGridView.getChildAt(1);
+        }
+
+        int firstTop = firstChild.getTop();
+
+        int distance = TouchUtils.dragViewBy(this, firstChild, 
+                Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 
+                (int) (mActivity.getWindowManager().getDefaultDisplay().getHeight() * 0.75f));
+        
+        assertEquals("View scrolled to wrong position", firstTop
+                + (distance - ViewConfiguration.getTouchSlop() - 1), firstChild.getTop());
+    } 
+    
+    @LargeTest
+    public void testManyScrolls() {
+        int originalCount = mGridView.getChildCount();
+        
+        View firstChild;
+        int firstId = Integer.MIN_VALUE;
+        int firstTop = Integer.MIN_VALUE; 
+        int prevId;
+        int prevTop; 
+        do {
+            prevId = firstId;
+            prevTop = firstTop;
+            TouchUtils.dragQuarterScreenDown(this);
+            assertTrue(String.format("Too many children created: %d expected no more than %d", 
+                    mGridView.getChildCount(), originalCount + 4), 
+                    mGridView.getChildCount() <= originalCount + 4);
+            firstChild = mGridView.getChildAt(0);
+            firstId = firstChild.getId();
+            firstTop = firstChild.getTop(); 
+        } while ((prevId != firstId) || (prevTop != firstTop));
+        
+        
+        firstChild = mGridView.getChildAt(0);
+        assertEquals("View scrolled to wrong position", 0, firstChild.getId());
+        
+        firstId = Integer.MIN_VALUE;
+        firstTop = Integer.MIN_VALUE; 
+        do {
+            prevId = firstId;
+            prevTop = firstTop;
+            TouchUtils.dragQuarterScreenUp(this);
+            assertTrue(String.format("Too many children created: %d expected no more than %d", 
+                    mGridView.getChildCount(), originalCount + 4), 
+                    mGridView.getChildCount() <= originalCount + 4);
+            firstChild = mGridView.getChildAt(0);
+            firstId = firstChild.getId();
+            firstTop = firstChild.getTop(); 
+        } while ((prevId != firstId) || (prevTop != firstTop));
+        
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        assertEquals("Grid is not scrolled to the bottom", mGridView.getAdapter().getCount() - 1,
+                lastChild.getId());
+    } 
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingTest.java
new file mode 100644
index 0000000..0b39909
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.gridview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridVerticalSpacing;
+
+public class GridTouchVerticalSpacingTest extends ActivityInstrumentationTestCase<GridVerticalSpacing> {
+    private GridVerticalSpacing mActivity;
+    private GridView mGridView;
+
+    public GridTouchVerticalSpacingTest() {
+        super("com.android.frameworktest", GridVerticalSpacing.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mGridView = getActivity().getGridView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mGridView);
+
+        assertEquals(0, mGridView.getSelectedItemPosition());
+    }
+
+    @MediumTest
+    public void testNoScroll() {
+        View firstChild = mGridView.getChildAt(0);
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        
+        int firstTop = firstChild.getTop();
+        
+        TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT, 
+                0, -(ViewConfiguration.getTouchSlop()));
+        
+        View newFirstChild = mGridView.getChildAt(0);
+        
+        assertEquals("View scrolled too early", firstTop, newFirstChild.getTop());
+        assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+    }
+    
+    @LargeTest
+    public void testShortScroll() {
+        View firstChild = mGridView.getChildAt(0);
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        
+        int firstTop = firstChild.getTop();
+        
+        TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT,
+                0, -(ViewConfiguration.getTouchSlop() + 1 + 10));
+        
+        View newFirstChild = mGridView.getChildAt(0);
+        
+        assertEquals("View scrolled to wrong position", firstTop, newFirstChild.getTop() + 10);
+        assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+    }
+    
+    @LargeTest
+    public void testLongScroll() {
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        
+        int lastTop = lastChild.getTop();
+        
+        int distance = TouchUtils.dragViewToY(this, lastChild, Gravity.TOP | Gravity.LEFT,
+                mGridView.getTop());
+        
+        assertEquals("View scrolled to wrong position", 
+                lastTop - (distance - ViewConfiguration.getTouchSlop() - 1), lastChild.getTop());
+    }
+    
+    @LargeTest
+    public void testManyScrolls() {
+        int originalCount = mGridView.getChildCount();
+        
+        View firstChild;
+        int firstId = Integer.MIN_VALUE;
+        int firstTop = Integer.MIN_VALUE; 
+        int prevId;
+        int prevTop; 
+        do {
+            prevId = firstId;
+            prevTop = firstTop;
+            TouchUtils.dragQuarterScreenUp(this);
+            assertTrue(String.format("Too many children created: %d expected no more than %d", 
+                    mGridView.getChildCount(), originalCount + 4), 
+                    mGridView.getChildCount() <= originalCount + 4);
+            firstChild = mGridView.getChildAt(0);
+            firstId = firstChild.getId();
+            firstTop = firstChild.getTop(); 
+        } while ((prevId != firstId) || (prevTop != firstTop));
+
+        
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        assertEquals("Grid is not scrolled to the bottom", mGridView.getAdapter().getCount() - 1,
+                lastChild.getId());
+        
+        firstId = Integer.MIN_VALUE;
+        firstTop = Integer.MIN_VALUE; 
+        do {
+            prevId = firstId;
+            prevTop = firstTop;
+            TouchUtils.dragQuarterScreenDown(this);
+            assertTrue(String.format("Too many children created: %d expected no more than %d", 
+                    mGridView.getChildCount(), originalCount + 4), 
+                    mGridView.getChildCount() <= originalCount + 4);
+            firstChild = mGridView.getChildAt(0);
+            firstId = firstChild.getId();
+            firstTop = firstChild.getTop(); 
+        } while ((prevId != firstId) || (prevTop != firstTop));
+        
+        firstChild = mGridView.getChildAt(0);
+        assertEquals("Grid is not scrolled to the top", 0, firstChild.getId());
+    } 
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutGravityTest.java
new file mode 100644
index 0000000..239bd7d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutGravityTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.frame;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.app.Activity;
+import android.view.View;
+import com.android.frameworktest.layout.frame.FrameLayoutGravity;
+import com.android.frameworktest.R;
+
+public class FrameLayoutGravityTest extends ActivityInstrumentationTestCase<FrameLayoutGravity> {
+    private View mLeftView;
+    private View mRightView;
+    private View mCenterHorizontalView;
+    private View mLeftCenterVerticalView;
+    private View mRighCenterVerticalView;
+    private View mCenterView;
+    private View mLeftBottomView;
+    private View mRightBottomView;
+    private View mCenterHorizontalBottomView;
+    private View mParent;
+
+    public FrameLayoutGravityTest() {
+        super("com.android.frameworktest", FrameLayoutGravity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+
+        mParent = activity.findViewById(R.id.parent);
+
+        mLeftView = activity.findViewById(R.id.left);
+        mRightView = activity.findViewById(R.id.right);
+        mCenterHorizontalView = activity.findViewById(R.id.center_horizontal);
+
+        mLeftCenterVerticalView = activity.findViewById(R.id.left_center_vertical);
+        mRighCenterVerticalView = activity.findViewById(R.id.right_center_vertical);
+        mCenterView = activity.findViewById(R.id.center);
+
+        mLeftBottomView = activity.findViewById(R.id.left_bottom);
+        mRightBottomView = activity.findViewById(R.id.right_bottom);
+        mCenterHorizontalBottomView = activity.findViewById(R.id.center_horizontal_bottom);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mParent);
+        assertNotNull(mLeftView);
+        assertNotNull(mRightView);
+        assertNotNull(mCenterHorizontalView);
+        assertNotNull(mLeftCenterVerticalView);
+        assertNotNull(mRighCenterVerticalView);
+        assertNotNull(mCenterView);
+        assertNotNull(mLeftBottomView);
+        assertNotNull(mRightBottomView);
+        assertNotNull(mCenterHorizontalBottomView);
+    }
+
+    @MediumTest
+    public void testLeftTopAligned() throws Exception {
+        ViewAsserts.assertLeftAligned(mParent, mLeftView);
+        ViewAsserts.assertTopAligned(mParent, mLeftView);
+    }
+
+    @MediumTest
+    public void testRightTopAligned() throws Exception {
+        ViewAsserts.assertRightAligned(mParent, mRightView);
+        ViewAsserts.assertTopAligned(mParent, mRightView);
+    }
+
+    @MediumTest
+    public void testCenterHorizontalTopAligned() throws Exception {
+        ViewAsserts.assertHorizontalCenterAligned(mParent, mCenterHorizontalView);
+        ViewAsserts.assertTopAligned(mParent, mCenterHorizontalView);
+    }
+
+    @MediumTest
+    public void testLeftCenterVerticalAligned() throws Exception {
+        ViewAsserts.assertLeftAligned(mParent, mLeftCenterVerticalView);
+        ViewAsserts.assertVerticalCenterAligned(mParent, mLeftCenterVerticalView);
+    }
+
+    @MediumTest
+    public void testRightCenterVerticalAligned() throws Exception {
+        ViewAsserts.assertRightAligned(mParent, mRighCenterVerticalView);
+        ViewAsserts.assertVerticalCenterAligned(mParent, mRighCenterVerticalView);
+    }
+
+    @MediumTest
+    public void testCenterAligned() throws Exception {
+        ViewAsserts.assertHorizontalCenterAligned(mParent, mCenterView);
+        ViewAsserts.assertVerticalCenterAligned(mParent, mCenterView);
+    }
+
+    @MediumTest
+    public void testLeftBottomAligned() throws Exception {
+        ViewAsserts.assertLeftAligned(mParent, mLeftBottomView);
+        ViewAsserts.assertBottomAligned(mParent, mLeftBottomView);
+    }
+
+    @MediumTest
+    public void testRightBottomAligned() throws Exception {
+        ViewAsserts.assertRightAligned(mParent, mRightBottomView);
+        ViewAsserts.assertBottomAligned(mParent, mRightBottomView);
+    }
+
+    @MediumTest
+    public void testCenterHorizontalBottomAligned() throws Exception {
+        ViewAsserts.assertHorizontalCenterAligned(mParent, mCenterHorizontalBottomView);
+        ViewAsserts.assertBottomAligned(mParent, mCenterHorizontalBottomView);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutMarginTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutMarginTest.java
new file mode 100644
index 0000000..4df4805
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutMarginTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.frame;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.app.Activity;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.frameworktest.layout.frame.FrameLayoutMargin;
+import com.android.frameworktest.R;
+
+public class FrameLayoutMarginTest extends ActivityInstrumentationTestCase<FrameLayoutMargin> {
+    private View mLeftView;
+    private View mRightView;
+    private View mTopView;
+    private View mBottomView;
+    private View mParent;
+
+    public FrameLayoutMarginTest() {
+        super("com.android.frameworktest", FrameLayoutMargin.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+
+        mParent = activity.findViewById(R.id.parent);
+
+        mLeftView = activity.findViewById(R.id.left);
+        mRightView = activity.findViewById(R.id.right);
+        mTopView = activity.findViewById(R.id.top);
+        mBottomView = activity.findViewById(R.id.bottom);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mParent);
+        assertNotNull(mLeftView);
+        assertNotNull(mRightView);
+        assertNotNull(mTopView);
+        assertNotNull(mBottomView);
+    }
+
+    @MediumTest
+    public void testLeftMarginAligned() throws Exception {
+        ViewAsserts.assertLeftAligned(mParent, mLeftView,
+                ((ViewGroup.MarginLayoutParams) mLeftView.getLayoutParams()).leftMargin);
+    }
+
+    @MediumTest
+    public void testRightMarginAligned() throws Exception {
+        ViewAsserts.assertRightAligned(mParent, mRightView,
+                ((ViewGroup.MarginLayoutParams) mRightView.getLayoutParams()).rightMargin);
+    }
+
+    @MediumTest
+    public void testTopMarginAligned() throws Exception {
+        ViewAsserts.assertTopAligned(mParent, mTopView,
+                ((ViewGroup.MarginLayoutParams) mTopView.getLayoutParams()).topMargin);
+    }
+
+    @MediumTest
+    public void testBottomMarginAligned() throws Exception {
+        ViewAsserts.assertBottomAligned(mParent, mBottomView,
+                ((ViewGroup.MarginLayoutParams) mBottomView.getLayoutParams()).bottomMargin);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravityTest.java
new file mode 100644
index 0000000..0b6360e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravityTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.BaselineAlignmentCenterGravity;
+
+public class BaselineAlignmentCenterGravityTest extends ActivityInstrumentationTestCase<BaselineAlignmentCenterGravity> {
+    private Button mButton1;
+    private Button mButton2;
+    private Button mButton3;
+
+    public BaselineAlignmentCenterGravityTest() {
+        super("com.android.frameworktest", BaselineAlignmentCenterGravity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+        mButton1 = (Button) activity.findViewById(R.id.button1);
+        mButton2 = (Button) activity.findViewById(R.id.button2);
+        mButton3 = (Button) activity.findViewById(R.id.button3);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mButton1);
+        assertNotNull(mButton2);
+        assertNotNull(mButton3);
+    }
+
+    @MediumTest
+    public void testChildrenAligned() throws Exception {
+        final View parent = (View) mButton1.getParent();
+        ViewAsserts.assertTopAligned(mButton1, parent);
+        ViewAsserts.assertTopAligned(mButton2, parent);
+        ViewAsserts.assertTopAligned(mButton3, parent);
+        ViewAsserts.assertBottomAligned(mButton1, parent);
+        ViewAsserts.assertBottomAligned(mButton2, parent);
+        ViewAsserts.assertBottomAligned(mButton3, parent);
+        ViewAsserts.assertTopAligned(mButton1, mButton2);
+        ViewAsserts.assertTopAligned(mButton2, mButton3);
+        ViewAsserts.assertBottomAligned(mButton1, mButton2);
+        ViewAsserts.assertBottomAligned(mButton2, mButton3);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentSpinnerButton.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentSpinnerButton.java
new file mode 100644
index 0000000..050e053
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentSpinnerButton.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.HorizontalOrientationVerticalAlignment;
+
+public class BaselineAlignmentSpinnerButton extends ActivityInstrumentationTestCase<HorizontalOrientationVerticalAlignment> {
+    private View mSpinner;
+    private View mButton;
+
+    public BaselineAlignmentSpinnerButton() {
+        super("com.android.frameworktest", HorizontalOrientationVerticalAlignment.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+        mSpinner = activity.findViewById(R.id.reminder_value);
+        mButton = activity.findViewById(R.id.reminder_remove);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mSpinner);
+        assertNotNull(mButton);
+    }
+
+    @MediumTest
+    public void testChildrenAligned() throws Exception {
+        ViewAsserts.assertBaselineAligned(mSpinner, mButton);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
new file mode 100644
index 0000000..a315d81
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.BaselineAlignmentZeroWidthAndWeight;
+import com.android.frameworktest.layout.linear.ExceptionTextView;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+public class BaselineAlignmentZeroWidthAndWeightTest extends ActivityInstrumentationTestCase<BaselineAlignmentZeroWidthAndWeight> {
+    private Button mShowButton;
+
+    public BaselineAlignmentZeroWidthAndWeightTest() {
+        super("com.android.frameworktest", BaselineAlignmentZeroWidthAndWeight.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+        mShowButton = (Button) activity.findViewById(R.id.show);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mShowButton);        
+    }
+
+    @MediumTest
+    public void testComputeTexViewWithoutIllegalArgumentException() throws Exception {
+        assertTrue(mShowButton.hasFocus());
+
+        // Pressing the button will show an ExceptionTextView that might set a failed bit if
+        // the test fails.
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();
+
+        final ExceptionTextView etv = (ExceptionTextView) getActivity()
+                .findViewById(R.id.routeToField);
+        assertFalse("exception test view should not fail", etv.isFailed());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineButtonsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineButtonsTest.java
new file mode 100644
index 0000000..9f2e138
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineButtonsTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.BaselineButtons;
+
+public class BaselineButtonsTest extends ActivityInstrumentationTestCase<BaselineButtons> {
+    private View mCurrentTime;
+    private View mTotalTime;
+    private ImageButton mPrev;
+    private ImageButton mNext;
+    private ImageButton mPause;
+    private View mLayout;
+
+    public BaselineButtonsTest() {
+        super("com.android.frameworktest", BaselineButtons.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+        mCurrentTime = activity.findViewById(R.id.currenttime);
+        mTotalTime = activity.findViewById(R.id.totaltime);
+        mPrev = (ImageButton) activity.findViewById(R.id.prev);
+        mNext = (ImageButton) activity.findViewById(R.id.next);
+        mPause = (ImageButton) activity.findViewById(R.id.pause);
+        mLayout = activity.findViewById(R.id.layout);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mCurrentTime);    
+        assertNotNull(mTotalTime);  
+        assertNotNull(mPrev);  
+        assertNotNull(mNext);  
+        assertNotNull(mPause);  
+        assertNotNull(mLayout);  
+    }
+    
+    @MediumTest
+    public void testLayout() {
+        int pauseHeight =  Math.max(mPause.getDrawable().getIntrinsicHeight()
+                + mPause.getPaddingTop() + mPause.getPaddingBottom(),
+                mPause.getBackground().getMinimumHeight());
+        int prevHeight = Math.max(mPrev.getDrawable().getIntrinsicHeight() + mPrev.getPaddingTop()
+                + mPrev.getPaddingBottom(),
+                mPrev.getBackground().getMinimumHeight());
+        int nextHeight = Math.max(mNext.getDrawable().getIntrinsicHeight() + mNext.getPaddingTop()
+                + mNext.getPaddingBottom(),
+                mNext.getBackground().getMinimumHeight());
+        assertEquals("Layout incorrect height", pauseHeight, mLayout.getHeight()); 
+        assertEquals("Pause incorrect height", pauseHeight, mPause.getHeight()); 
+        assertEquals("Prev incorrect height", prevHeight, mPrev.getHeight()); 
+        assertEquals("Next incorrect height", nextHeight, mNext.getHeight()); 
+        assertEquals("Pause wrong top", 0, mPause.getTop()); 
+        assertEquals("Prev wrong top", (pauseHeight - prevHeight) / 2, mPrev.getTop());
+        assertEquals("Next wrong top", (pauseHeight - nextHeight) / 2, mNext.getTop());
+        assertEquals("CurrentTime wrong bottom",  pauseHeight, mCurrentTime.getBottom());
+        assertEquals("TotalTime wrong bottom",  pauseHeight, mTotalTime.getBottom());
+        assertTrue("CurrentTime too tall", mCurrentTime.getTop() > 0);
+        assertTrue("TotalTime too tall", mTotalTime.getTop() > 0);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/FillInWrapTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/FillInWrapTest.java
new file mode 100644
index 0000000..0e7a4a0
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/FillInWrapTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+import com.android.frameworktest.R;
+
+public class FillInWrapTest extends ActivityInstrumentationTestCase<FillInWrap> {
+    private View mChild;
+    private View mContainer;
+
+    public FillInWrapTest() {
+        super("com.android.frameworktest", FillInWrap.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+        mChild = activity.findViewById(R.id.data);
+        mContainer = activity.findViewById(R.id.layout);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mChild);
+        assertNotNull(mContainer);
+    }
+
+    @MediumTest
+    public void testLayout() {
+        assertTrue("the child's height should be less than the parent's",
+                mChild.getMeasuredHeight() < mContainer.getMeasuredHeight());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/LinearLayoutEditTextsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/LinearLayoutEditTextsTest.java
new file mode 100644
index 0000000..9dde62c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/LinearLayoutEditTextsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.layout.linear;
+
+import com.android.frameworktest.layout.linear.LinearLayoutEditTexts;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.app.Activity;
+
+public class LinearLayoutEditTextsTest extends ActivityInstrumentationTestCase<LinearLayoutEditTexts> {
+    private View mChild;
+    private View mContainer;
+
+    public LinearLayoutEditTextsTest() {
+        super("com.android.frameworktest", LinearLayoutEditTexts.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+        mChild = activity.findViewById(R.id.editText1);
+        mContainer = activity.findViewById(R.id.layout);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mChild);
+        assertNotNull(mContainer);
+    }
+
+    @MediumTest
+    public void testLayout() {
+        final int childHeight = mChild.getHeight();
+        final int containerHeight = mContainer.getHeight();
+
+        assertEquals(containerHeight, childHeight);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightSumTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightSumTest.java
new file mode 100644
index 0000000..a51743b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightSumTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.WeightSum;
+
+public class WeightSumTest extends ActivityInstrumentationTestCase<WeightSum> {
+    private View mChild;
+    private View mContainer;
+
+    public WeightSumTest() {
+        super("com.android.frameworktest", WeightSum.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+        mChild = activity.findViewById(R.id.child);
+        mContainer = activity.findViewById(R.id.container);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mChild);
+        assertNotNull(mContainer);
+    }
+
+    @MediumTest
+    public void testLayout() {
+        final int childWidth = mChild.getWidth();
+        final int containerWidth = mContainer.getWidth();
+
+        assertEquals(containerWidth / 2, childWidth);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightTest.java
new file mode 100644
index 0000000..f7fec78
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.Weight;
+
+public class WeightTest extends ActivityInstrumentationTestCase<Weight> {
+    private View mChild;
+    private View mContainer;
+
+    public WeightTest() {
+        super("com.android.frameworktest", Weight.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Activity activity = getActivity();
+        mChild = activity.findViewById(R.id.child4);
+        mContainer = activity.findViewById(R.id.layout);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mChild);
+        assertNotNull(mContainer);
+    }
+
+    @MediumTest
+    public void testLayout() {
+        ViewAsserts.assertRightAligned(mChild, mContainer);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/AddColumnTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/AddColumnTest.java
new file mode 100644
index 0000000..9d713c8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/AddColumnTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.AddColumn;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+
+/**
+ * {@link com.android.frameworktest.layout.table.AddColumn} is
+ * setup to exercise the case of adding row programmatically in a table.
+ */
+public class AddColumnTest extends ActivityInstrumentationTestCase<AddColumn> {
+    private Button mAddRow;
+    private TableLayout mTable;
+
+    public AddColumnTest() {
+        super("com.android.frameworktest", AddColumn.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final AddColumn activity = getActivity();
+        mAddRow = (Button) activity.findViewById(R.id.add_row_button);
+        mTable = (TableLayout) activity.findViewById(R.id.table);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mAddRow);
+        assertNotNull(mTable);
+        assertTrue(mAddRow.hasFocus());
+    }
+
+    @MediumTest
+    public void testWidths() throws Exception {
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();
+
+        TableRow row1 = (TableRow) mTable.getChildAt(0);
+        TableRow row2 = (TableRow) mTable.getChildAt(1);
+
+        assertTrue(row1.getChildCount() < row2.getChildCount());
+
+        for (int i = 0; i < row1.getChildCount(); i++) {
+            assertEquals(row2.getChildAt(i).getWidth(), row1.getChildAt(i).getWidth());
+        }
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/CellSpanTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/CellSpanTest.java
new file mode 100644
index 0000000..85f9c2c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/CellSpanTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.CellSpan;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.CellSpan} is
+ * setup to exercise tables in which cells use spanning.
+ */
+public class CellSpanTest extends ActivityInstrumentationTestCase<CellSpan> {
+    private View mA;
+    private View mB;
+    private View mC;
+    private View mSpanThenCell;
+    private View mCellThenSpan;
+    private View mSpan;
+
+    public CellSpanTest() {
+        super("com.android.frameworktest", CellSpan.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final CellSpan activity = getActivity();
+        mA            = activity.findViewById(R.id.a);
+        mB            = activity.findViewById(R.id.b);
+        mC            = activity.findViewById(R.id.c);
+        mSpanThenCell = activity.findViewById(R.id.spanThenCell);
+        mCellThenSpan = activity.findViewById(R.id.cellThenSpan);
+        mSpan         = activity.findViewById(R.id.span);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mA);
+        assertNotNull(mB);
+        assertNotNull(mC);
+        assertNotNull(mSpanThenCell);
+        assertNotNull(mCellThenSpan);
+        assertNotNull(mSpan);
+    }
+
+    @MediumTest
+    public void testSpanThenCell() throws Exception {
+        int spanWidth = mA.getMeasuredWidth() + mB.getMeasuredWidth();
+        assertEquals("span followed by cell is broken", spanWidth,
+                mSpanThenCell.getMeasuredWidth());
+    }
+
+    @MediumTest
+    public void testCellThenSpan() throws Exception {
+        int spanWidth = mB.getMeasuredWidth() + mC.getMeasuredWidth();
+        assertEquals("cell followed by span is broken", spanWidth,
+                mCellThenSpan.getMeasuredWidth());
+    }
+
+    @MediumTest
+    public void testSpan() throws Exception {
+        int spanWidth = mA.getMeasuredWidth() + mB.getMeasuredWidth() +
+                mC.getMeasuredWidth();
+        assertEquals("span is broken", spanWidth, mSpan.getMeasuredWidth());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/FixedWidthTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/FixedWidthTest.java
new file mode 100644
index 0000000..a54d503
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/FixedWidthTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.FixedWidth;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.FixedWidth} is
+ * setup to exercise tables in which cells use fixed width and height.
+ */
+public class FixedWidthTest extends ActivityInstrumentationTestCase<FixedWidth> {
+    private View mFixedWidth;
+    private View mFixedHeight;
+    private View mNonFixedWidth;
+
+    public FixedWidthTest() {
+        super("com.android.frameworktest", FixedWidth.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final FixedWidth activity = getActivity();
+        mFixedWidth = activity.findViewById(R.id.fixed_width);
+        mNonFixedWidth = activity.findViewById(R.id.non_fixed_width);
+        mFixedHeight = activity.findViewById(R.id.fixed_height);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mFixedWidth);
+        assertNotNull(mFixedHeight);
+        assertNotNull(mNonFixedWidth);
+    }
+
+    @MediumTest
+    public void testFixedWidth() throws Exception {
+        assertEquals(150, mFixedWidth.getWidth());
+        assertEquals(mFixedWidth.getWidth(), mNonFixedWidth.getWidth());
+    }
+
+    @MediumTest
+    public void testFixedHeight() throws Exception {
+        assertEquals(48, mFixedHeight.getHeight());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/HorizontalGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/HorizontalGravityTest.java
new file mode 100644
index 0000000..1355cb3
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/HorizontalGravityTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.HorizontalGravity;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.HorizontalGravity} is
+ * setup to exercise tables in which cells use horizontal gravity.
+ */
+public class HorizontalGravityTest extends ActivityInstrumentationTestCase<HorizontalGravity> {
+    private View mReference;
+    private View mCenter;
+    private View mBottomRight;
+    private View mLeft;
+
+    public HorizontalGravityTest() {
+        super("com.android.frameworktest", HorizontalGravity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final HorizontalGravity activity = getActivity();
+        mReference   = activity.findViewById(R.id.reference);
+        mCenter      = activity.findViewById(R.id.center);
+        mBottomRight = activity.findViewById(R.id.bottomRight);
+        mLeft        = activity.findViewById(R.id.left);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mReference);
+        assertNotNull(mCenter);
+        assertNotNull(mBottomRight);
+        assertNotNull(mLeft);
+    }
+
+    @MediumTest
+    public void testCenterGravity() throws Exception {
+        ViewAsserts.assertHorizontalCenterAligned(mReference, mCenter);
+    }
+
+    @MediumTest
+    public void testLeftGravity() throws Exception {
+        ViewAsserts.assertLeftAligned(mReference, mLeft);
+    }
+
+    @MediumTest
+    public void testRightGravity() throws Exception {
+        ViewAsserts.assertRightAligned(mReference, mBottomRight);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java
new file mode 100644
index 0000000..de3e68b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.VerticalGravity;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.VerticalGravity} is
+ * setup to exercise tables in which cells use vertical gravity.
+ */
+public class VerticalGravityTest extends ActivityInstrumentationTestCase<VerticalGravity> {
+    private View mReference1;
+    private View mReference2;
+    private View mReference3;
+    private View mTop;
+    private View mCenter;
+    private View mBottom;
+
+    public VerticalGravityTest() {
+        super("com.android.frameworktest", VerticalGravity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final VerticalGravity activity = getActivity();
+        mReference1 = activity.findViewById(R.id.reference1);
+        mReference2 = activity.findViewById(R.id.reference2);
+        mReference3 = activity.findViewById(R.id.reference3);
+        mTop        = activity.findViewById(R.id.cell_top);
+        mCenter     = activity.findViewById(R.id.cell_center);
+        mBottom     = activity.findViewById(R.id.cell_bottom);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mReference1);
+        assertNotNull(mReference2);
+        assertNotNull(mReference3);
+        assertNotNull(mTop);
+        assertNotNull(mCenter);
+        assertNotNull(mBottom);
+    }
+
+    @MediumTest
+    public void testTopGravity() throws Exception {
+        ViewAsserts.assertTopAligned(mReference1, mTop);
+    }
+
+    @MediumTest
+    public void testCenterGravity() throws Exception {
+        ViewAsserts.assertVerticalCenterAligned(mReference2, mCenter);
+    }
+
+    @MediumTest
+    public void testBottomGravity() throws Exception {
+        ViewAsserts.assertBottomAligned(mReference3, mBottom);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/WeightTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/WeightTest.java
new file mode 100644
index 0000000..9e20686
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/WeightTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.Weight;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.Weight} is
+ * setup to exercise tables in which cells use a weight.
+ */
+public class WeightTest extends ActivityInstrumentationTestCase<Weight> {
+    private View mCell1;
+    private View mCell2;
+    private View mCell3;
+    private View mRow;
+
+    public WeightTest() {
+        super("com.android.frameworktest", Weight.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        final Weight activity = getActivity();
+        mCell1 = activity.findViewById(R.id.cell1);
+        mCell3 = activity.findViewById(R.id.cell2);
+        mCell2 = activity.findViewById(R.id.cell3);
+        mRow = activity.findViewById(R.id.row);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mCell1);
+        assertNotNull(mCell2);
+        assertNotNull(mCell3);
+        assertNotNull(mRow);
+    }
+
+    @MediumTest
+    public void testAllCellsFillParent() throws Exception {
+        assertEquals(mCell1.getWidth() + mCell2.getWidth() + mCell3.getWidth(), mRow.getWidth());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityManyTest.java
new file mode 100644
index 0000000..d36e343
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityManyTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListBottomGravityMany;
+
+public class ListBottomGravityManyTest extends ActivityInstrumentationTestCase<ListBottomGravityMany> {
+    private ListBottomGravityMany mActivity;
+    private ListView mListView;
+
+    public ListBottomGravityManyTest() {
+        super("com.android.frameworktest", ListBottomGravityMany.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        // Last item should be selected
+        assertEquals(mListView.getAdapter().getCount() - 1, mListView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityTest.java
new file mode 100644
index 0000000..79556cf
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListBottomGravity;
+
+public class ListBottomGravityTest extends ActivityInstrumentationTestCase<ListBottomGravity> {
+    private ListBottomGravity mActivity;
+    private ListView mListView;
+
+    public ListBottomGravityTest() {
+        super("com.android.frameworktest", ListBottomGravity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        // Last item should be selected
+        assertEquals(mListView.getAdapter().getCount() - 1, mListView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListEmptyViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListEmptyViewTest.java
new file mode 100644
index 0000000..ca12154
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListEmptyViewTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+
+public class ListEmptyViewTest extends ActivityInstrumentationTestCase<ListWithEmptyView> {
+    private ListWithEmptyView mActivity;
+    private ListView mListView;
+
+
+    public ListEmptyViewTest() {
+        super("com.android.frameworktest", ListWithEmptyView.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        assertTrue("Empty view not shown", mListView.getVisibility() == View.GONE);
+    }
+    
+    @MediumTest
+    public void testZeroToOne() {
+        Instrumentation inst = getInstrumentation();
+       
+        inst.invokeMenuActionSync(mActivity, mActivity.MENU_ADD, 0);
+        inst.waitForIdleSync();
+        assertTrue("Empty view still shown", mActivity.getEmptyView().getVisibility() == View.GONE);
+        assertTrue("List not shown", mActivity.getListView().getVisibility() == View.VISIBLE);
+    }
+    
+    @MediumTest
+    public void testZeroToOneForwardBack() {
+        Instrumentation inst = getInstrumentation();
+       
+        inst.invokeMenuActionSync(mActivity, mActivity.MENU_ADD, 0);
+        inst.waitForIdleSync();
+        assertTrue("Empty view still shown", mActivity.getEmptyView().getVisibility() == View.GONE);
+        assertTrue("List not shown", mActivity.getListView().getVisibility() == View.VISIBLE);
+        
+        // Navigate forward
+        Intent intent = new Intent();
+        intent.setClass(mActivity, ListWithEmptyView.class);
+        mActivity.startActivity(intent);
+        
+        // Navigate backward
+        inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+        inst.waitForIdleSync();
+        assertTrue("Empty view still shown", mActivity.getEmptyView().getVisibility() == View.GONE);
+        assertTrue("List not shown", mActivity.getListView().getVisibility() == View.VISIBLE);
+
+    }
+    
+    @LargeTest
+    public void testZeroToManyToZero() {
+        Instrumentation inst = getInstrumentation();
+       
+        int i;
+
+        for (i = 0; i < 10; i++) {
+            inst.invokeMenuActionSync(mActivity, mActivity.MENU_ADD, 0);
+            inst.waitForIdleSync();
+            assertTrue("Empty view still shown",
+                    mActivity.getEmptyView().getVisibility() == View.GONE);
+            assertTrue("List not shown", mActivity.getListView().getVisibility() == View.VISIBLE);
+        }
+
+        for (i = 0; i < 10; i++) {
+            inst.invokeMenuActionSync(mActivity, mActivity.MENU_REMOVE, 0);
+            inst.waitForIdleSync();
+            if (i < 9) {
+                assertTrue("Empty view still shown",
+                        mActivity.getEmptyView().getVisibility() == View.GONE);
+                assertTrue("List not shown",
+                        mActivity.getListView().getVisibility() == View.VISIBLE);
+            } else {
+                assertTrue("Empty view not shown",
+                        mActivity.getEmptyView().getVisibility() == View.VISIBLE);
+                assertTrue("List still shown",
+                        mActivity.getListView().getVisibility() == View.GONE);
+            }
+        }
+        
+        // Navigate forward
+        Intent intent = new Intent();
+        intent.setClass(mActivity, ListWithEmptyView.class);
+        mActivity.startActivity(intent);
+        
+        // Navigate backward
+        inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+        inst.waitForIdleSync();
+        assertTrue("Empty view not shown", mActivity.getEmptyView().getVisibility() == View.VISIBLE);
+        assertTrue("List still shown", mActivity.getListView().getVisibility() == View.GONE);
+    }
+    
+    
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListFocusableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListFocusableTest.java
new file mode 100644
index 0000000..1bb1f1c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListFocusableTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.widget.ListAdapter;
+import android.widget.ArrayAdapter;
+
+public class ListFocusableTest extends ActivityInstrumentationTestCase<ListTopGravity> {
+    private ListTopGravity mActivity;
+    private ListView mListView;
+
+    public ListFocusableTest() {
+        super("com.android.frameworktest", ListTopGravity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+
+        // First item should be selected
+        assertEquals(0, mListView.getSelectedItemPosition());
+    }
+
+    @MediumTest
+    public void testAdapterFull() {
+        setFullAdapter();
+        assertTrue(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testAdapterEmpty() {
+        setEmptyAdapter();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testAdapterNull() {
+        setNullAdapter();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testAdapterFullSetFocusable() {
+        assertTrue(mListView.isFocusable());
+
+        setFocusable();
+        assertTrue(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testAdapterFullSetNonFocusable() {
+        assertTrue(mListView.isFocusable());
+
+        setNonFocusable();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testAdapterEmptySetFocusable() {
+        setEmptyAdapter();
+        assertFalse(mListView.isFocusable());
+
+        setFocusable();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testAdapterEmptySetNonFocusable() {
+        setEmptyAdapter();
+        assertFalse(mListView.isFocusable());
+
+        setNonFocusable();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testAdapterNullSetFocusable() {
+        setNullAdapter();
+        assertFalse(mListView.isFocusable());
+
+        setFocusable();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testAdapterNullSetNonFocusable() {
+        setNullAdapter();
+        assertFalse(mListView.isFocusable());
+
+        setNonFocusable();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testFocusableSetAdapterFull() {
+        assertTrue(mListView.isFocusable());
+
+        setFullAdapter();
+        assertTrue(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testNonFocusableSetAdapterFull() {
+        assertTrue(mListView.isFocusable());
+
+        setNonFocusable();
+        assertFalse(mListView.isFocusable());
+
+        setFullAdapter();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testFocusableSetAdapterEmpty() {
+        assertTrue(mListView.isFocusable());
+
+        setEmptyAdapter();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testNonFocusableSetAdapterEmpty() {
+        assertTrue(mListView.isFocusable());
+
+        setNonFocusable();
+        assertFalse(mListView.isFocusable());
+
+        setEmptyAdapter();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testFocusableSetAdapterNull() {
+        assertTrue(mListView.isFocusable());
+
+        setNullAdapter();
+        assertFalse(mListView.isFocusable());
+    }
+
+    @MediumTest
+    public void testNonFocusableSetAdapterNull() {
+        assertTrue(mListView.isFocusable());
+
+        setNonFocusable();
+        assertFalse(mListView.isFocusable());
+
+        setNullAdapter();
+        assertFalse(mListView.isFocusable());
+    }
+
+    private ListAdapter createFullAdapter() {
+        return new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1,
+                new String[] { "Android", "Robot" });
+    }
+
+    private ListAdapter createEmptyAdapter() {
+        return new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1,
+                new String[] { });
+    }
+
+
+    private void setFullAdapter() {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setAdapter(createFullAdapter());
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+
+    private void setEmptyAdapter() {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setAdapter(createEmptyAdapter());
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+
+    private void setNullAdapter() {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setAdapter(null);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+
+    private void setFocusable() {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setFocusable(true);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+
+    private void setNonFocusable() {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setFocusable(false);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListHeterogeneousTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListHeterogeneousTest.java
new file mode 100644
index 0000000..0e48993
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListHeterogeneousTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListHeterogeneous;
+
+public class ListHeterogeneousTest extends ActivityInstrumentationTestCase<ListHeterogeneous> {
+    private ListHeterogeneous mActivity;
+    private ListView mListView;
+
+
+    public ListHeterogeneousTest() {
+        super("com.android.frameworktest", ListHeterogeneous.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+    }
+    
+    @LargeTest
+    public void testKeyScrolling() {
+        Instrumentation inst = getInstrumentation();
+        
+        int count = mListView.getAdapter().getCount();
+
+        
+        for (int i = 0; i < count - 1; i++) {
+            inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        inst.waitForIdleSync();
+        int convertMissesBefore = mActivity.getConvertMisses();
+        
+        assertEquals("Unexpected convert misses", 0, convertMissesBefore);
+        
+        for (int i = 0; i < count - 1; i++) {
+            inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
+        }
+        inst.waitForIdleSync();
+        int convertMissesAfter = mActivity.getConvertMisses();
+        
+        assertEquals("Unexpected convert misses", 0, convertMissesAfter);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInHorizontalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInHorizontalTest.java
new file mode 100644
index 0000000..1432576
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInHorizontalTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.listview.ListInHorizontal;
+
+public class ListInHorizontalTest extends ListUnspecifiedMeasure<ListInHorizontal> {
+    public ListInHorizontalTest() {
+        super(ListInHorizontal.class);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInVerticalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInVerticalTest.java
new file mode 100644
index 0000000..73078b9
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInVerticalTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.listview.ListInVertical;
+
+public class ListInVerticalTest extends ListUnspecifiedMeasure<ListInVertical> {
+    public ListInVerticalTest() {
+        super(ListInVertical.class);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListItemRequestRectAboveThinFirstItemTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListItemRequestRectAboveThinFirstItemTest.java
new file mode 100644
index 0000000..16c4d39
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListItemRequestRectAboveThinFirstItemTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.graphics.Rect;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListOfThinItems;
+
+public class ListItemRequestRectAboveThinFirstItemTest
+        extends ActivityInstrumentationTestCase<ListOfThinItems> {
+    private ListView mListView;
+
+    public ListItemRequestRectAboveThinFirstItemTest() {
+        super("com.android.frameworktest", ListOfThinItems.class);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+
+        assertTrue("first child needs to be within fading edge height",
+                mListView.getChildAt(0).getBottom() < mListView.getVerticalFadingEdgeLength());
+        assertTrue("should be at least two visible children",
+                mListView.getChildCount() >= 2);
+    }
+
+    // reproduce bug 998501: when first item fits within fading edge,
+    // having the second item call requestRectangleOnScreen with a rect above
+    // the bounds of the list, it was scrolling too far
+    @MediumTest
+    public void testSecondItemRequestRectAboveTop() throws Exception {
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("selected position", 1, mListView.getSelectedItemPosition());
+
+        final View second = mListView.getChildAt(1);
+        final Rect rect = new Rect();
+        second.getDrawingRect(rect);
+        rect.offset(0, -2 * second.getBottom());
+
+        getActivity().requestRectangleOnScreen(1, rect);
+        getInstrumentation().waitForIdleSync();        
+
+        assertEquals("top of first item",
+                mListView.getListPaddingTop(), mListView.getChildAt(0).getTop());
+
+    }
+
+    // same thing, but at bottom
+    @LargeTest
+    public void testSecondToLastItemRequestRectBelowBottom() throws Exception {
+
+        final int secondToLastPos = mListView.getCount() - 2;
+
+        while (mListView.getSelectedItemPosition() < secondToLastPos) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals("selected position", secondToLastPos,
+                mListView.getSelectedItemPosition());
+
+        final View secondToLast = mListView.getSelectedView();
+        final Rect rect = new Rect();
+        secondToLast.getDrawingRect(rect);
+        rect.offset(0,
+                2 * (mListView.getBottom() - secondToLast.getTop()));
+
+        final int secondToLastIndex = mListView.getChildCount() - 2;
+        getActivity().requestRectangleOnScreen(secondToLastIndex, rect);
+        getInstrumentation().waitForIdleSync();
+
+        int listBottom = mListView.getHeight() - mListView.getPaddingBottom();
+        assertEquals("bottom of last item should be at bottom of list",
+                listBottom,
+                mListView.getChildAt(mListView.getChildCount() - 1).getBottom());
+    }
+
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListManagedCursorTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListManagedCursorTest.java
new file mode 100644
index 0000000..0251dfb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListManagedCursorTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import android.test.TouchUtils;
+
+/**
+ * Tests restoring the scroll position in a list with a managed cursor.
+ */
+public class ListManagedCursorTest extends ActivityInstrumentationTestCase<ListManagedCursor> {
+    private ListManagedCursor mActivity;
+    private ListView mListView;
+
+    public ListManagedCursorTest() {
+        super("com.android.frameworktest", ListManagedCursor.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        assertEquals(0, mListView.getFirstVisiblePosition());
+    }
+    
+    /**
+     * Scroll the list using arrows, launch new activity, hit back, make sure we're still scrolled.
+     */
+    @LargeTest
+    public void testKeyScrolling() {
+        Instrumentation inst = getInstrumentation();
+        
+        int firstVisiblePosition = arrowScroll(inst);
+        
+        inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+        inst.waitForIdleSync();
+        
+        assertTrue("List changed to touch mode", !mListView.isInTouchMode()); 
+        assertTrue("List did not preserve scroll position", 
+                firstVisiblePosition == mListView.getFirstVisiblePosition()); 
+    }
+
+    /**
+     * Scroll the list using touch, launch new activity, hit back, make sure we're still scrolled.
+     */
+    @LargeTest
+    public void testTouchScrolling() {
+        Instrumentation inst = getInstrumentation();
+        
+       int firstVisiblePosition = touchScroll(inst);
+        
+        inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+        inst.waitForIdleSync();
+        
+        assertTrue("List not in touch mode", mListView.isInTouchMode()); 
+        assertTrue("List did not preserve scroll position", 
+                firstVisiblePosition == mListView.getFirstVisiblePosition()); 
+    }
+    
+    /**
+     * Scroll the list using arrows, launch new activity, change to touch mode, hit back, make sure
+     * we're still scrolled.
+     */
+    @LargeTest
+    public void testKeyScrollingToTouchMode() {
+        Instrumentation inst = getInstrumentation();
+        
+        int firstVisiblePosition = arrowScroll(inst);
+        
+        TouchUtils.dragQuarterScreenUp(this);
+        inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+        inst.waitForIdleSync();
+        
+        assertTrue("List did not change to touch mode", mListView.isInTouchMode()); 
+        assertTrue("List did not preserve scroll position", 
+                firstVisiblePosition == mListView.getFirstVisiblePosition()); 
+    }
+
+
+    /**
+     * Scroll the list using touch, launch new activity, change to trackball mode, hit back, make
+     * sure we're still scrolled.
+     */
+    @FlakyTest(tolerance=3)
+    @LargeTest
+    public void testTouchScrollingToTrackballMode() {
+        Instrumentation inst = getInstrumentation();
+
+        int firstVisiblePosition = touchScroll(inst);
+
+        inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        inst.waitForIdleSync();
+        inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        inst.waitForIdleSync();
+        inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+        inst.waitForIdleSync();
+        assertTrue("List not in trackball mode", !mListView.isInTouchMode());
+        assertTrue("List did not preserve scroll position", firstVisiblePosition == mListView
+                .getFirstVisiblePosition());
+    }
+    
+    public int arrowScroll(Instrumentation inst) {
+        int count = mListView.getChildCount();
+
+        for (int i = 0; i < count * 2; i++) {
+            inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        inst.waitForIdleSync();
+
+        int firstVisiblePosition = mListView.getFirstVisiblePosition();
+        assertTrue("Arrow scroll did not happen", firstVisiblePosition > 0);
+        assertTrue("List still in touch mode", !mListView.isInTouchMode());
+
+        inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_CENTER);
+        inst.waitForIdleSync();
+
+        try {
+            Thread.sleep(3000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        return firstVisiblePosition;
+    }
+
+    public int touchScroll(Instrumentation inst) {
+        TouchUtils.dragQuarterScreenUp(this);
+        inst.waitForIdleSync();
+        TouchUtils.dragQuarterScreenUp(this);
+        inst.waitForIdleSync();
+        TouchUtils.dragQuarterScreenUp(this);
+        inst.waitForIdleSync();
+        TouchUtils.dragQuarterScreenUp(this);
+        inst.waitForIdleSync();
+
+        int firstVisiblePosition = mListView.getFirstVisiblePosition();
+        assertTrue("Touch scroll did not happen", firstVisiblePosition > 0);
+        assertTrue("List not in touch mode", mListView.isInTouchMode());
+
+        TouchUtils.clickView(this, mListView.getChildAt(mListView.getChildCount() - 1));
+        inst.waitForIdleSync();
+
+        try {
+            Thread.sleep(3000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        return firstVisiblePosition;
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListRetainsFocusAcrossLayoutsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListRetainsFocusAcrossLayoutsTest.java
new file mode 100644
index 0000000..02a8beb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListRetainsFocusAcrossLayoutsTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.listview.ListItemFocusablesClose;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+public class ListRetainsFocusAcrossLayoutsTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
+
+    public ListRetainsFocusAcrossLayoutsTest() {
+        super("com.android.frameworktest", ListItemFocusablesClose.class);
+    }
+
+    private void requestLayoutOnList() {
+        getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                getActivity().getListView().requestLayout();
+            }
+        });
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("top button at position 0 should be focused",
+                getActivity().getChildOfItem(0, 0).isFocused());
+    }
+
+    @MediumTest
+    public void testBottomButtonRetainsFocusAfterLayout() throws Exception {
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertTrue("bottom botton at position 0 should be focused",
+                getActivity().getChildOfItem(0, 2).isFocused());
+
+        requestLayoutOnList();
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("bottom botton at position 0 should be focused after layout",
+                getActivity().getChildOfItem(0, 2).isFocused());
+    }
+
+    @MediumTest
+    public void testTopButtonOfSecondPositionRetainsFocusAfterLayout() {
+        sendRepeatedKeys(2, KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertTrue("top botton at position 1 should be focused",
+                getActivity().getChildOfItem(1, 0).isFocused());
+
+        requestLayoutOnList();
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("top botton at position 1 should be focused after layout",
+                getActivity().getChildOfItem(1, 0).isFocused());
+
+    }
+
+    @MediumTest
+    public void testBottomButtonOfSecondPositionRetainsFocusAfterLayout() {
+        sendRepeatedKeys(3, KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertTrue("bottom botton at position 1 should be focused",
+                getActivity().getChildOfItem(1, 2).isFocused());
+
+        requestLayoutOnList();
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("bottom botton at position 1 should be focused after layout",
+                getActivity().getChildOfItem(1, 2).isFocused());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java
new file mode 100644
index 0000000..44958d9
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.AbsListView;
+import android.widget.ListView;
+
+import android.test.TouchUtils;
+
+public class ListScrollListenerTest extends ActivityInstrumentationTestCase<ListScrollListener> implements
+        AbsListView.OnScrollListener {
+    private ListScrollListener mActivity;
+    private ListView mListView;
+    private int mFirstVisibleItem = -1;
+    private int mVisibleItemCount = -1;
+    private int mTotalItemCount = -1;
+
+    public ListScrollListenerTest() {
+        super("com.android.frameworktest", ListScrollListener.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+        mListView.setOnScrollListener(this);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        assertEquals(0, mFirstVisibleItem);
+    }
+    
+    @LargeTest
+    public void testKeyScrolling() {
+        Instrumentation inst = getInstrumentation();
+        
+        int firstVisibleItem = mFirstVisibleItem;
+        for (int i = 0; i < mVisibleItemCount * 2; i++) {
+            inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        inst.waitForIdleSync();
+        assertTrue("Arrow scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+        
+        firstVisibleItem = mFirstVisibleItem;
+        inst.sendCharacterSync(KeyEvent.KEYCODE_SPACE);
+        inst.waitForIdleSync();
+        assertTrue("Page scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+        
+        firstVisibleItem = mFirstVisibleItem;
+        KeyEvent down = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, 
+                KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON);
+        KeyEvent up = new KeyEvent(0, 0, KeyEvent.ACTION_UP, 
+                KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON);
+        inst.sendKeySync(down);
+        inst.sendKeySync(up);
+        inst.waitForIdleSync();
+        
+        assertTrue("Full scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+        assertEquals("Full scroll did not happen", mTotalItemCount, 
+                mFirstVisibleItem + mVisibleItemCount);    
+    }
+
+    @LargeTest
+    public void testTouchScrolling() {
+        int firstVisibleItem = mFirstVisibleItem;
+        TouchUtils.dragQuarterScreenUp(this);
+        TouchUtils.dragQuarterScreenUp(this);
+        assertTrue("Touch scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+    }
+
+    
+    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+        mFirstVisibleItem = firstVisibleItem;
+        mVisibleItemCount = visibleItemCount;
+        mTotalItemCount = totalItemCount;
+    }
+
+    public void onScrollStateChanged(AbsListView view, int scrollState) {        
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java
new file mode 100644
index 0000000..e35d894
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+/**
+ * Basic tests of setting & clearing the selection
+ */
+public class ListSetSelectionTest extends ActivityInstrumentationTestCase2<ListSimple> {
+    private ListSimple mActivity;
+    private ListView mListView;
+
+    public ListSetSelectionTest() {
+        super("com.android.frameworktest", ListSimple.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+    }
+    
+    /** Confirm that we can set the selection to each specific position */
+    @MediumTest
+    @UiThreadTest
+    public void testSetSelection() {
+        // Set the selection to each position
+        int childCount = mListView.getChildCount();
+        for (int i=0; i<childCount; i++) {
+            mListView.setSelection(i);
+            assertEquals("Set selection", i, mListView.getSelectedItemPosition());
+        }
+    }
+    
+    /** Confirm that you cannot unset the selection using the same API */
+    @MediumTest
+    @UiThreadTest
+    public void testClearSelection() {
+        // Set the selection to first position
+        mListView.setSelection(0);
+        assertEquals("Set selection", 0, mListView.getSelectedItemPosition());
+
+        // Clear the selection
+        mListView.setSelection(ListView.INVALID_POSITION);
+        assertEquals("Set selection", 0, mListView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListUnspecifiedMeasure.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListUnspecifiedMeasure.java
new file mode 100644
index 0000000..55a57ef
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListUnspecifiedMeasure.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.app.Activity;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+public class ListUnspecifiedMeasure<T extends Activity> extends ActivityInstrumentationTestCase<T> {
+    private T mActivity;
+    private ListView mListView;
+
+    protected ListUnspecifiedMeasure(Class<T> klass) {
+        super("com.android.frameworktest", klass);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = (ListView) mActivity.findViewById(R.id.list);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+    }
+
+    @MediumTest
+    public void testWasMeasured() {
+        assertTrue(mListView.getMeasuredWidth() > 0);
+        assertTrue(mListView.getWidth() > 0);
+        assertTrue(mListView.getMeasuredHeight() > 0);
+        assertTrue(mListView.getHeight() > 0);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListViewHeightTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListViewHeightTest.java
new file mode 100644
index 0000000..d5bdf8b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListViewHeightTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.listview.ListViewHeight;
+
+public class ListViewHeightTest extends ActivityInstrumentationTestCase<ListViewHeight> {
+    private ListViewHeight mActivity;
+
+
+    public ListViewHeightTest() {
+        super("com.android.frameworktest", ListViewHeight.class);
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+    }
+
+    @MediumTest
+    public void testButtons() {
+        Instrumentation inst = getInstrumentation();
+        final Button button1 = (Button) mActivity.findViewById(R.id.button1);
+        final Button button2 = (Button) mActivity.findViewById(R.id.button2);
+        final Button button3 = (Button) mActivity.findViewById(R.id.button3);
+        
+
+        ListView list = (ListView) mActivity.findViewById(R.id.inner_list);
+        assertEquals("Unexpected items in adapter", 0, list.getCount());
+        assertEquals("Unexpected children in list view", 0, list.getChildCount());
+        
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                button1.performClick();
+            }
+        });
+        inst.waitForIdleSync();
+        assertTrue("List not be visible after clicking button1", list.isShown());
+        assertTrue("List incorrect height", list.getHeight() == 200);
+        
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                button2.performClick();
+            }
+        });
+        inst.waitForIdleSync();
+        assertTrue("List not be visible after clicking button2", list.isShown());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                button3.performClick();
+            }
+        });
+        inst.waitForIdleSync();
+        assertFalse("List should not be visible clicking button3", list.isShown());
+    }
+    
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListInterleaveFocusablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListInterleaveFocusablesTest.java
new file mode 100644
index 0000000..1fe75c4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListInterleaveFocusablesTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.frameworktest.listview.ListInterleaveFocusables;
+import com.android.frameworktest.util.ListUtil;
+
+public class ListInterleaveFocusablesTest extends ActivityInstrumentationTestCase<ListInterleaveFocusables> {
+    private ListView mListView;
+    private ListUtil mListUtil;
+
+    public ListInterleaveFocusablesTest() {
+        super("com.android.frameworktest", ListInterleaveFocusables.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mListView = getActivity().getListView();
+        mListUtil = new ListUtil(mListView, getInstrumentation());
+    }
+
+    @LargeTest
+    public void testPreconditions() {
+        assertEquals(7, mListView.getChildCount());
+        assertTrue(mListView.getChildAt(1).isFocusable());
+        assertTrue(mListView.getChildAt(3).isFocusable());
+        assertTrue(mListView.getChildAt(6).isFocusable());
+    }
+
+    @MediumTest
+    public void testGoingFromUnFocusableSelectedToFocusable() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals("selected item position", 1, mListView.getSelectedItemPosition());
+        assertSelectedViewFocus(true);
+    }
+
+    // go down from an item that isn't focusable, make sure it finds the focusable
+    // below (instead of above).  this exposes a (now fixed) bug where the focus search
+    // was not starting from the right spot
+    @MediumTest
+    public void testGoingDownFromUnFocusableSelectedToFocusableWithOtherFocusableAbove() {
+        mListUtil.setSelectedPosition(2);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("selected item position", 3, mListView.getSelectedItemPosition());
+        assertSelectedViewFocus(true);
+    }
+
+    // same, but going up
+    @MediumTest
+    public void testGoingUpFromUnFocusableSelectedToFocusableWithOtherFocusableAbove() {
+        mListUtil.setSelectedPosition(2);
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("selected item position", 1, mListView.getSelectedItemPosition());
+        assertSelectedViewFocus(true);
+    }
+
+    /**
+     * Go down from a focusable when there is a focusable below, but it is more than
+     * one item away; make sure it won't give that item focus because it is too far away.
+     */
+    @MediumTest
+    public void testGoingDownFromFocusableToUnfocusableWhenFocusableIsBelow() {
+        mListUtil.setSelectedPosition(3);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("selected item position", 4, mListView.getSelectedItemPosition());
+        assertSelectedViewFocus(false);
+    }
+
+    // same but going up
+    @MediumTest
+    public void testGoingUpFromFocusableToUnfocusableWhenFocusableIsBelow() {
+        mListUtil.setSelectedPosition(6);
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("selected item position", 5, mListView.getSelectedItemPosition());
+        assertSelectedViewFocus(false);
+    }
+
+    public void assertSelectedViewFocus(boolean isFocused) {
+        final View view = mListView.getSelectedView();
+        assertEquals("selected view focused", isFocused, view.isFocused());
+        assertEquals("selected position's isSelected should be the inverse "
+                + "of it having focus", !isFocused, view.isSelected());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
new file mode 100644
index 0000000..6ff9181
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListItemFocusableAboveUnfocusable;
+
+public class ListItemFocusableAboveUnfocusableTest extends ActivityInstrumentationTestCase<ListItemFocusableAboveUnfocusable> {
+    private ListView mListView;
+
+    public ListItemFocusableAboveUnfocusableTest() {
+        super("com.android.frameworktest", ListItemFocusableAboveUnfocusable.class);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mListView = getActivity().getListView();
+    }
+
+
+    @MediumTest
+    public void testPreconditions() {
+        assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+        assertTrue(mListView.getChildAt(0).isFocused());
+        assertFalse(mListView.getChildAt(1).isFocusable());
+    }
+
+    @MediumTest
+    public void testMovingToUnFocusableTakesFocusAway() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertFalse("focused item should have lost focus",
+                mListView.getChildAt(0).isFocused());
+        assertEquals("selected position", 1, mListView.getSelectedItemPosition());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesCloseTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesCloseTest.java
new file mode 100644
index 0000000..07356ba
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesCloseTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListItemFocusablesClose;
+
+public class ListItemFocusablesCloseTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
+    private ListView mListView;
+    private int mListTop;
+    private int mListBottom;
+
+    public ListItemFocusablesCloseTest() {
+        super("com.android.frameworktest", ListItemFocusablesClose.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception{
+        super.setUp();
+        mListView = getActivity().getListView();
+        mListTop = mListView.getListPaddingTop();
+        mListBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mListView);
+        assertTrue(mListView.getAdapter().areAllItemsEnabled());
+        assertTrue(mListView.getItemsCanFocus());
+        assertEquals(0, mListView.getSelectedItemPosition());
+        final LinearLayout first = (LinearLayout) mListView.getSelectedView();
+        getInstrumentation().waitForIdleSync();
+        assertEquals("first item should be at top of screen",
+                mListView.getListPaddingTop(),
+                first.getTop());
+        assertTrue("first button of first list item should have focus",
+                first.getChildAt(0).isFocused());
+        assertTrue("item should be shorter than list for this test to make sense",
+                first.getHeight() < mListView.getHeight());
+        assertEquals("two items should be on screen",
+                2, mListView.getChildCount());
+        assertTrue("first button of second item should be on screen",
+                getActivity().getChildOfItem(1, 0).getBottom() < mListBottom);
+    }
+
+
+    @MediumTest
+    public void testChangeFocusWithinItem() {
+        final LinearLayout first = (LinearLayout) mListView.getSelectedView();
+        final int topOfFirstItemBefore = first.getTop();
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue("focus should have moved to second button of first item",
+                first.getChildAt(2).isFocused());
+        assertEquals("selection should not have changed",
+                0, mListView.getSelectedItemPosition());
+        assertEquals("list item should not have been shifted",
+                topOfFirstItemBefore, first.getTop());
+
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue("focus should have moved back to first button of first item",
+                first.getChildAt(0).isFocused());
+        assertEquals("list item should not have been shifted",
+                topOfFirstItemBefore, first.getTop());
+    }
+
+    @MediumTest
+    public void testMoveDownToButtonInDifferentSelection() {
+        final LinearLayout first = (LinearLayout) mListView.getSelectedView();
+        final int topOfFirstItemBefore = first.getTop();
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals("selection should have moved to second item",
+                1, mListView.getSelectedItemPosition());
+        final LinearLayout selectedItem = (LinearLayout) mListView.getSelectedView();
+        assertTrue("first button of second item should have focus",
+                selectedItem.getChildAt(0).isFocused());
+        assertEquals("list item should not have been shifted",
+                topOfFirstItemBefore, first.getTop());
+    }
+
+    @MediumTest
+    public void testMoveUpToButtonInDifferentSelection() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(1, mListView.getSelectedItemPosition());
+        assertTrue("first button of second item should have focus",
+                getActivity().getChildOfItem(1, 0).hasFocus());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("first list item should have selection", 0,
+                mListView.getSelectedItemPosition());
+        assertTrue("second button of first item should have focus",
+                getActivity().getChildOfItem(0, 2).hasFocus());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesFarApartTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesFarApartTest.java
new file mode 100644
index 0000000..951e021
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesFarApartTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListItemFocusablesFarApart;
+
+public class ListItemFocusablesFarApartTest extends ActivityInstrumentationTestCase<ListItemFocusablesFarApart> {
+    private ListView mListView;
+    private int mListTop;
+    private int mListBottom;
+
+    public ListItemFocusablesFarApartTest() {
+        super("com.android.frameworktest", ListItemFocusablesFarApart.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mListView = getActivity().getListView();
+        mListTop = mListView.getListPaddingTop();
+        mListBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+    }
+
+    /**
+     * Get the child of a list item.
+     * @param listIndex The index of the currently visible items
+     * @param index The index of the child.
+     */
+    public View getChildOfItem(int listIndex, int index) {
+        return ((ViewGroup) mListView.getChildAt(listIndex)).getChildAt(index);
+
+    }
+
+    public int getTopOfChildOfItem(int listIndex, int index) {
+        ViewGroup listItem = (ViewGroup) mListView.getChildAt(listIndex);
+        View child = listItem.getChildAt(index);
+        return child.getTop() + listItem.getTop();
+    }
+
+    public int getBottomOfChildOfItem(int listIndex, int index) {
+        ViewGroup listItem = (ViewGroup) mListView.getChildAt(listIndex);
+        View child = listItem.getChildAt(index);
+        return child.getBottom() + listItem.getTop();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mListView);
+        assertEquals("should only be one visible list item",
+                1, mListView.getChildCount());
+        int topOfFirstButton = getTopOfChildOfItem(0, 0);
+        int topOfSecondButton = getTopOfChildOfItem(0, 2);
+        assertTrue("second button should be more than max scroll away from first",
+                topOfSecondButton - topOfFirstButton > mListView.getMaxScrollAmount());
+    }
+
+
+    @MediumTest
+    public void testPanWhenNextFocusableTooFarDown() {
+
+        int expectedTop = mListView.getChildAt(0).getTop();
+
+        final Button topButton = (Button) getChildOfItem(0, 0);
+
+        int counter = 0;
+        while(getTopOfChildOfItem(0, 2) > mListBottom) {
+            // just to make sure we never end up with an infinite loop
+            if (counter > 5) fail("couldn't reach next button within " + counter + " downs");
+
+            if (getBottomOfChildOfItem(0, 0) < mListTop) {
+                assertFalse("after " + counter + " downs, top button not visible, should not have focus",
+                        topButton.isFocused());
+                assertFalse("after " + counter + " downs, neither top button nor botom button visible, nothng within first list " +
+                        "item should have focus", mListView.getChildAt(0).hasFocus());
+            } else {
+                assertTrue("after " + counter + " downs, top button still visible, should have focus",
+                        topButton.isFocused());
+            }
+
+            assertEquals("after " + counter + " downs, " +
+                    "should have panned by max scroll amount",
+                    expectedTop, mListView.getChildAt(0).getTop());
+
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            expectedTop -= mListView.getMaxScrollAmount();
+            counter++;
+        }
+
+        // at this point, the second button is visible on screen.
+        // it should have focus
+        assertTrue("second button should have focus",
+                getChildOfItem(0, 2).isFocused());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemsExpandOnSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
new file mode 100644
index 0000000..f61ce7b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListItemsExpandOnSelection;
+
+public class ListItemsExpandOnSelectionTest extends ActivityInstrumentationTestCase<ListItemsExpandOnSelection> {
+    private ListView mListView;
+    private int mListTop;
+    private int mListBottom;
+    private int mExpandedHeight;
+    private int mNormalHeight;
+
+    public ListItemsExpandOnSelectionTest() {
+        super("com.android.frameworktest",
+                ListItemsExpandOnSelection.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mListView = getActivity().getListView();
+        mListTop = mListView.getListPaddingTop();
+        mListBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+        mExpandedHeight = mListView.getChildAt(0).getHeight();
+        mNormalHeight = mListView.getChildAt(1).getHeight();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertEquals(0, mListView.getSelectedItemPosition());
+        assertEquals("selected item should be 1.5 times taller than the others",
+                mExpandedHeight, (int) (mNormalHeight * 1.5));
+    }
+
+    @MediumTest
+    public void testMoveSelectionDownNotRequiringScroll() {
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals(1, mListView.getSelectedItemPosition());
+        assertEquals("first item's top should not have shifted",
+                mListTop, mListView.getChildAt(0).getTop());
+
+    }
+
+    @MediumTest
+    public void testMoveSelectionUpNotRequiringScroll() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals(1, mListView.getSelectedItemPosition());
+        final int oldBottom = mListView.getSelectedView().getBottom();
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+        assertEquals("bottom of 2nd itme should have stayed the same when " +
+                "moving back up",
+                oldBottom,
+                mListView.getChildAt(1).getBottom());
+    }
+
+    @MediumTest
+    public void testMoveSelectionDownRequiringScroll() {
+        int lastItemIndex = mListView.getChildCount() - 1;
+
+        for(int i = 0; i < lastItemIndex; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        getInstrumentation().waitForIdleSync();
+
+        assertEquals("list position", lastItemIndex, mListView.getSelectedItemPosition());
+        assertEquals("expanded height", mExpandedHeight, mListView.getSelectedView().getHeight());
+        assertEquals("should be above bottom fading edge",
+                mListBottom - mListView.getVerticalFadingEdgeLength(),
+                mListView.getSelectedView().getBottom());
+    }
+
+    @LargeTest
+    public void testMoveSelectionUpRequiringScroll() {
+        int childrenPerScreen = mListView.getChildCount();
+
+        // go down past last child on screen
+        for(int i = 0; i < childrenPerScreen; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        // go back up to second to last
+        for(int i = 0; i < childrenPerScreen - 1; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        }
+        getInstrumentation().waitForIdleSync();
+
+        assertEquals("list position", 1, mListView.getSelectedItemPosition());
+        assertEquals("expanded height", mExpandedHeight, mListView.getSelectedView().getHeight());
+        assertEquals("should be below top fading edge",
+                mListTop + mListView.getVerticalFadingEdgeLength(),
+                mListView.getSelectedView().getTop());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
new file mode 100644
index 0000000..38f4b0e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.View;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListLastItemPartiallyVisible;
+
+public class ListLastItemPartiallyVisibleTest extends ActivityInstrumentationTestCase<ListLastItemPartiallyVisible> {
+    private ListView mListView;
+    private int mListBottom;
+
+
+    public ListLastItemPartiallyVisibleTest() {
+        super("com.android.frameworktest", ListLastItemPartiallyVisible.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mListView = getActivity().getListView();
+        mListBottom = mListView.getHeight() - mListView.getPaddingBottom();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertEquals("number of elements visible should be the same as number of items " +
+                "in adapter", mListView.getCount(), mListView.getChildCount());
+
+        final View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        assertTrue("last item should be partially off screen",
+                lastChild.getBottom() > mListBottom);
+        assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+    }
+
+    // reproduce bug 998094
+    @MediumTest
+    public void testMovingDownToFullyVisibleNoScroll() {
+        final View firstChild = mListView.getChildAt(0);
+        final int firstBottom = firstChild.getBottom();
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("shouldn't have scrolled: bottom of first child changed.",
+                firstBottom, firstChild.getBottom());
+    }
+
+    // reproduce bug 998094
+    @MediumTest
+    public void testMovingUpToFullyVisibleNoScroll() {
+        int numMovesToLast = mListView.getCount() - 1;
+        for (int i = 0; i < numMovesToLast; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals("should have moved to last position",
+                mListView.getChildCount() - 1, mListView.getSelectedItemPosition());
+
+        final View lastChild = mListView.getSelectedView();
+        final int lastTop = lastChild.getTop();
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("shouldn't have scrolled: top of last child changed.",
+                lastTop, lastChild.getTop());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
new file mode 100644
index 0000000..126eea2
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.android.frameworktest.listview.ListOfItemsShorterThanScreen;
+
+public class ListOfItemsShorterThanScreenTest
+        extends ActivityInstrumentationTestCase<ListOfItemsShorterThanScreen> {
+    private ListView mListView;
+    private ListOfItemsShorterThanScreen mActivity;
+
+
+    public ListOfItemsShorterThanScreenTest() {
+        super("com.android.frameworktest", ListOfItemsShorterThanScreen.class);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertEquals(0, mListView.getSelectedItemPosition());
+        assertTrue(mListView.getChildAt(0).isSelected());
+        assertEquals(mListView.getListPaddingTop(), mListView.getSelectedView().getTop());
+    }
+
+    @MediumTest
+    public void testMoveDownToOnScreenNextItem() {
+        final View next = mListView.getChildAt(1);
+        assertFalse(next.isSelected());
+        final int secondPosition = mListView.getSelectedView().getBottom();
+        assertEquals("second item should be positioned item height pixels from top.",
+                secondPosition,
+                next.getTop());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(1, mListView.getSelectedItemPosition());
+        assertTrue(next.isSelected());
+        assertEquals("next selected item shouldn't have moved",
+                secondPosition,
+                next.getTop());
+    }
+
+    @MediumTest
+    public void testMoveUpToOnScreenItem() {
+        // move down one, then back up
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals(0, mListView.getSelectedItemPosition());
+    }
+
+    @MediumTest
+    public void testMoveDownToItemRequiringScrolling() {
+        final int lastOnScreenItemIndex = mListView.getChildCount() - 1;
+        final View lastItem = mListView.getChildAt(lastOnScreenItemIndex);
+        assertTrue("last item should be partially off screen",
+                lastItem.getBottom() > mListView.getBottom());
+        assertEquals(mListView.getListPaddingTop(), mListView.getSelectedView().getTop());
+
+        for (int i = 0; i < lastOnScreenItemIndex; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        assertEquals(lastOnScreenItemIndex, mListView.getSelectedItemPosition());
+        assertEquals(
+                getTopOfBottomFadingEdge(),
+                mListView.getSelectedView().getBottom());
+
+        // there should be a peeking view
+
+        // the current view isn't the last anymore...
+        assertEquals(mListView.getSelectedView(), mListView.getChildAt(mListView.getChildCount() - 2));
+
+        // peeking view is now last
+        final TextView view = (TextView) mListView.getChildAt(mListView.getChildCount() - 1);
+        assertEquals(mActivity.getValueAtPosition(lastOnScreenItemIndex + 1), view.getText());
+        assertFalse(view.isSelected());
+    }
+
+    @MediumTest
+    public void testMoveUpToItemRequiringScrolling() {
+        // go down to one past last item, then back up to the second item.  this will
+        // require scrolling to get it back on screen, and will need a peeking edge
+
+        int numItemsOnScreen = mListView.getChildCount();
+        for (int i = 0; i < numItemsOnScreen; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        for (int i = 0; i < numItemsOnScreen - 1; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        }
+
+        assertEquals(1, mListView.getSelectedItemPosition());
+        assertEquals("top should be just below vertical fading edge",
+                mListView.getVerticalFadingEdgeLength() + mListView.getListPaddingTop(),
+                mListView.getSelectedView().getTop());
+    }
+
+    @MediumTest
+    public void testPressUpWhenAlreadyAtTop() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+        assertEquals(0, mListView.getSelectedItemPosition());
+    }
+
+    @MediumTest
+    public void testPressDownWhenAlreadyAtBottom() {
+        final int lastItemPosition = mListView.getAdapter().getCount() - 1;
+        for (int i = 0; i < lastItemPosition; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals(lastItemPosition, mListView.getSelectedItemPosition());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(lastItemPosition, mListView.getSelectedItemPosition());
+    }
+
+    @MediumTest
+    public void testNoVerticalFadingEdgeWhenMovingToBottom() {
+        final int lastItemPosition = mListView.getAdapter().getCount() - 1;
+        for (int i = 0; i < lastItemPosition; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals(lastItemPosition, mListView.getSelectedItemPosition());
+
+        assertEquals("bottom of last item should be just above padding; no fading edge.",
+                mListView.getHeight() - mListView.getListPaddingBottom(),
+                mListView.getSelectedView().getBottom());
+
+    }
+
+    // the top of the bottom fading edge takes into account the list padding at the bottom,
+    // and the fading edge size
+    private int getTopOfBottomFadingEdge() {
+        return mListView.getHeight() - (mListView.getVerticalFadingEdgeLength() + mListView.getListPaddingBottom());
+    }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
new file mode 100644
index 0000000..ec3a15c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.View;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListOfItemsTallerThanScreen;
+
+public class ListOfItemsTallerThanScreenTest
+        extends ActivityInstrumentationTestCase<ListOfItemsTallerThanScreen> {
+
+    private ListView mListView;
+    private ListOfItemsTallerThanScreen mActivity;
+
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    public ListOfItemsTallerThanScreenTest() {
+        super("com.android.frameworktest", ListOfItemsTallerThanScreen.class);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mListView);
+        assertEquals("should only be one visible child", 1, mListView.getChildCount());
+        final int amountOffScreen = mListView.getChildAt(0).getBottom() - (mListView.getBottom() - mListView.getListPaddingBottom());
+        assertTrue("must be more than max scroll off screen for this test to work",
+                amountOffScreen > mListView.getMaxScrollAmount());
+    }
+
+    @MediumTest
+    public void testScrollDownAcrossItem() {
+        final View view = mListView.getSelectedView();
+        assertTrue(view.isSelected());
+
+        assertEquals(mListView.getListPaddingTop(),
+                view.getTop());
+
+        assertTrue("view must be taller than screen for this test to be worth anything",
+                view.getBottom() > mListView.getBottom());
+
+        // scroll down until next view is peeking ahead
+        int numScrollsUntilNextViewVisible = getNumDownPressesToScrollDownAcrossSelected();
+
+        for (int i = 0; i < numScrollsUntilNextViewVisible; i++) {
+            assertEquals("after " + i + " down scrolls across tall item",
+                    mListView.getListPaddingTop() - mListView.getMaxScrollAmount() * i,
+                    view.getTop());
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        // at this point, next view should be on screen peeking ahead, but we haven't given
+        // it selection yet
+        assertEquals("child count", 2, mListView.getChildCount());
+        assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+        assertTrue("same view should be selected", view.isSelected());
+        final View peekingView = mListView.getChildAt(1);
+        assertEquals(view.getBottom(), peekingView.getTop());
+    }
+
+    @MediumTest
+    public void testScrollDownToNextItem() {
+        final int numPresses = getNumDownPressesToScrollDownAcrossSelected();
+        assertEquals(1, mListView.getChildCount());
+
+        for (int i = 0; i < numPresses; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        // remember top of peeking child
+        final int topOfPeekingNext = mListView.getChildAt(1).getTop();
+
+        // next view is peeking, now press one more time
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        // old view should not have selection
+        assertFalse(mListView.getChildAt(0).isSelected());
+
+        // next view should now have selection, and be scrolled another a third of the list
+        // height
+        assertEquals(2, mListView.getChildCount());
+        final View next = mListView.getChildAt(1);
+        assertTrue("has selection", next.isSelected());
+        assertEquals(topOfPeekingNext - (mListView.getMaxScrollAmount()), next.getTop());
+    }
+
+    @MediumTest
+    public void testScrollFirstItemOffScreen() {
+        int numDownsToGetFirstItemOffScreen =
+                (mListView.getSelectedView().getHeight() / mListView.getMaxScrollAmount()) + 1;
+
+        for (int i = 0; i < numDownsToGetFirstItemOffScreen; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        getInstrumentation().waitForIdleSync();
+
+        assertEquals("should be at next item",
+                1, mListView.getSelectedItemPosition());
+
+        final int listTop = mListView.getTop() + mListView.getListPaddingTop();
+        assertTrue("top of selected view should be above top of list",
+                mListView.getSelectedView().getTop() < listTop);
+
+        assertEquals("off screen item shouldn't be a child of list view",
+                1, mListView.getChildCount());
+    }
+
+    @LargeTest
+    public void testScrollDownToLastItem() {
+        final int numItems = mListView.getAdapter().getCount();
+
+        int maxDowns = 20;
+        while (mListView.getSelectedItemPosition() < (numItems - 1)) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            if (--maxDowns <= 0) {
+                fail("couldn't get to last item within 20 down arrows");
+            }
+        }
+        getInstrumentation().waitForIdleSync();
+
+        // press down enough times to get to bottom of last item
+        final int numDownsLeft = getNumDownPressesToScrollDownAcrossSelected();
+        assertTrue(numDownsLeft > 0);
+        for (int i = 0; i < numDownsLeft; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        // one more time to get across last item
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        getInstrumentation().waitForIdleSync();
+
+        assertEquals(numItems - 1, mListView.getSelectedItemPosition());
+        final int realBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+        assertEquals(realBottom, mListView.getSelectedView().getBottom());
+
+        assertEquals("views scrolled off screen should be removed from view group",
+                1, mListView.getChildCount());
+    }
+
+    @MediumTest
+    public void testScrollUpAcrossFirstItem() {
+        final int listTop = mListView.getListPaddingTop();
+        assertEquals(listTop, mListView.getSelectedView().getTop());
+        final int numPresses = getNumDownPressesToScrollDownAcrossSelected();
+        for (int i = 0; i < numPresses; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals(2, mListView.getChildCount());
+        for (int i = 0; i < numPresses; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+            assertEquals(1, mListView.getChildCount());
+        }
+        assertEquals(listTop, mListView.getSelectedView().getTop());
+    }
+
+    /**
+     * Assuming the selected view is overlapping the bottom edge, how many times
+     * do I have to press down to get beyond it so that either:
+     * a) the next view is peeking in
+     * b) the selected view is the last item in the list, and we are scrolled to the bottom
+     * @return
+     */
+    private int getNumDownPressesToScrollDownAcrossSelected() {
+        View selected = mListView.getSelectedView();
+        int realBottom = mListView.getBottom() - mListView.getListPaddingBottom();
+        assertTrue("view should be overlapping bottom",
+                selected.getBottom() > realBottom);
+        assertTrue("view should be overlapping bottom",
+                selected.getTop() < realBottom);
+
+        int pixelsOffScreen = selected.getBottom() - realBottom;
+        return (pixelsOffScreen / mListView.getMaxScrollAmount()) + 1;
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortShortTallShortShortTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
new file mode 100644
index 0000000..e218099
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListOfShortShortTallShortShort;
+import com.android.frameworktest.util.ListUtil;
+
+public class ListOfShortShortTallShortShortTest extends ActivityInstrumentationTestCase<ListOfShortShortTallShortShort> {
+    private ListView mListView;
+    private ListUtil mListUtil;
+
+    public ListOfShortShortTallShortShortTest() {
+        super("com.android.frameworktest", ListOfShortShortTallShortShort.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mListView = getActivity().getListView();
+        mListUtil = new ListUtil(mListView, getInstrumentation());
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertEquals("list item count", 5, mListView.getCount());
+        assertEquals("list visible child count", 3, mListView.getChildCount());
+        int firstTwoHeight = mListView.getChildAt(0).getHeight() + mListView.getChildAt(1).getHeight();
+        assertTrue("first two items should fit within fading edge",
+                firstTwoHeight <= mListView.getVerticalFadingEdgeLength());
+        assertTrue("first two items should fit within list max scroll",
+                firstTwoHeight <= mListView.getMaxScrollAmount());
+    }
+
+    @MediumTest
+    public void testFadeTopTwoItemsOut() {
+        // put 2nd item selected
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        // one more to get two items scrolled off
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals("selected item position", 2, mListView.getSelectedItemPosition());
+        assertTrue("selected item top should be above list top",
+                mListView.getSelectedView().getTop() < mListUtil.getListTop());
+        assertTrue("selected item bottom should be below list bottom",
+                mListView.getSelectedView().getBottom() > mListUtil.getListBottom());
+        assertEquals("should only be 1 child of list (2 should have been scrolled off and removed",
+                1, mListView.getChildCount());
+    }
+
+    @LargeTest
+    public void testFadeInTwoBottomItems() {
+        // put 2nd item selected
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        // one more to get two items scrolled off
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("number of list children", 1, mListView.getChildCount());
+
+        // last down brings bottom two items into view
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("should have scrolled two extra views onto screen",
+                3, mListView.getChildCount());
+        assertEquals("new view position", 3, mListView.getChildAt(1).getId());
+        assertEquals("new view position", 4, mListView.getChildAt(2).getId());
+
+        assertTrue("bottom most view shouldn't be above list bottom",
+                mListView.getChildAt(2).getBottom() >= mListUtil.getListBottom());
+    }
+
+    @LargeTest
+    public void testFadeOutBottomTwoItems() throws Exception {
+        mListUtil.arrowScrollToSelectedPosition(4);
+
+        // go up to tall item
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+        // one more time to scroll off bottom two items
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+
+        assertEquals("selected item position", 2, mListView.getSelectedItemPosition());
+        assertTrue("selected item top should be at or above list top",
+                mListView.getSelectedView().getTop() <= mListUtil.getListTop());
+        assertTrue("selected item bottom should be below list bottom",
+                mListView.getSelectedView().getBottom() > mListUtil.getListBottom());
+        assertEquals("should only be 1 child of list (2 should have been scrolled off and removed",
+                1, mListView.getChildCount());        
+    }
+
+    @LargeTest
+    public void testFadeInTopTwoItems() throws Exception {
+        mListUtil.arrowScrollToSelectedPosition(4);
+
+        // put 2nd item selected
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+        // one more to get two items scrolled off
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("number of list children", 1, mListView.getChildCount());
+
+        // last down brings top two items into view
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("should have scrolled two extra views onto screen",
+                3, mListView.getChildCount());
+        assertEquals("new view position", 0, mListView.getChildAt(0).getId());
+        assertEquals("new view position", 1, mListView.getChildAt(1).getId());
+
+        assertTrue("top most view shouldn't be above list top",
+                mListView.getChildAt(0).getTop() <= mListUtil.getListTop());
+    }
+
+    
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortTallShortTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortTallShortTest.java
new file mode 100644
index 0000000..6a83ada
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortTallShortTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListOfShortTallShort;
+
+public class ListOfShortTallShortTest extends ActivityInstrumentationTestCase<ListOfShortTallShort> {
+    private ListView mListView;
+
+    public ListOfShortTallShortTest() {
+        super("com.android.frameworktest", ListOfShortTallShort.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("second item should be taller than screen",
+                mListView.getChildAt(1).getHeight() > mListView.getHeight());
+    }
+
+    @MediumTest
+    public void testGoDownFromShortToTall() {
+        int topBeforeMove = mListView.getChildAt(1).getTop();
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals("selection should have moved to tall item below",
+                1, mListView.getSelectedItemPosition());
+        assertEquals("should not have scrolled; top should be the same.",
+                topBeforeMove,
+                mListView.getSelectedView().getTop());
+    }
+
+    @MediumTest
+    public void testGoUpFromShortToTall() {
+        int maxMoves = 8;
+        while (mListView.getSelectedItemPosition() != 2 && maxMoves > 0) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals("couldn't get to 3rd item",
+                2,
+                mListView.getSelectedItemPosition());
+
+        assertEquals("should only be two items on screen",
+                2, mListView.getChildCount());
+        assertEquals("selected item should be last item on screen",
+                mListView.getChildAt(1), mListView.getSelectedView());
+
+        final int bottomBeforeMove = mListView.getChildAt(0).getBottom();
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("should have moved selection to tall item above",
+                1, mListView.getSelectedItemPosition());
+        assertEquals("should not have scrolled, top should be the same",
+                bottomBeforeMove,
+                mListView.getChildAt(0).getBottom());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfThinItemsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfThinItemsTest.java
new file mode 100644
index 0000000..e8dbbec
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfThinItemsTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListOfThinItems;
+
+public class ListOfThinItemsTest extends ActivityInstrumentationTestCase<ListOfThinItems> {
+    private ListView mListView;
+
+    public ListOfThinItemsTest() {
+        super("com.android.frameworktest", ListOfThinItems.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception{
+        super.setUp();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mListView);
+        assertTrue("need item height less than fading edge length",
+                mListView.getSelectedView().getHeight() < mListView.getVerticalFadingEdgeLength());
+        assertTrue("need items off screen",
+                mListView.getChildCount() < mListView.getAdapter().getCount());
+    }
+
+    @LargeTest
+    public void testScrollToBottom() {
+        final int numItems = mListView.getAdapter().getCount();
+        final int listBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+        for (int i = 0; i < numItems; i++) {
+            assertEquals("wrong selection at position " + i,
+                    i, mListView.getSelectedItemPosition());
+            final int bottomFadingEdge = listBottom - mListView.getVerticalFadingEdgeLength();
+            final View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+            final int lastVisiblePosition = lastChild.getId();
+
+
+            int bottomThreshold = (lastVisiblePosition < mListView.getAdapter().getCount() - 1) ?
+                    bottomFadingEdge : listBottom;
+
+            String prefix = "after " + i + " down presses, ";
+
+            assertTrue(prefix + "selected item is below bottom threshold (fading edge or bottom as " +
+                    "appropriate)",
+                    mListView.getSelectedView().getBottom() <= bottomThreshold);
+            assertTrue(prefix + "first item in list must be at very top or just above",
+                    mListView.getChildAt(0).getTop() <= 0);
+            assertTrue(prefix + "last item in list should be at very bottom or just below",
+                    lastChild.getBottom() >= listBottom);
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+    }
+
+    @LargeTest
+    public void testScrollToTop() {
+        final int numItems = mListView.getAdapter().getCount();
+
+        for (int i = 0; i < numItems - 1; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals("should have moved to last position",
+                numItems - 1, mListView.getSelectedItemPosition());
+
+        int listTop = mListView.getListPaddingTop();
+        final int listBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+
+        for (int i = 0; i < numItems; i++) {
+            int expectedPostion = numItems - (i + 1);
+            assertEquals("wrong selection at position " + expectedPostion,
+                    expectedPostion, mListView.getSelectedItemPosition());
+            final int topFadingEdge = listTop + mListView.getVerticalFadingEdgeLength();
+            final View firstChild = mListView.getChildAt(0);
+            final View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+            final int firstVisiblePosition = firstChild.getId();
+
+
+            int topThreshold = (firstVisiblePosition > 0) ?
+                    topFadingEdge : listTop;
+
+            String prefix = "after " + i + " up presses, ";
+
+            assertTrue(prefix + "selected item is above top threshold (fading edge or top as " +
+                    "appropriate)",
+                    mListView.getSelectedView().getTop() >= topThreshold);
+            assertTrue(prefix + "first item in list must be at very top or just above",
+                    firstChild.getTop() <= 0);
+            assertTrue(prefix + "last item in list should be at very bottom or just below",
+                    lastChild.getBottom() >= listBottom);
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        }
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
new file mode 100644
index 0000000..307c39d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * 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.frameworktest.listview.arrowscroll;
+
+import com.android.frameworktest.listview.ListWithFirstScreenUnSelectable;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import android.widget.AdapterView;
+
+public class ListWithFirstScreenUnSelectableTest
+        extends ActivityInstrumentationTestCase2<ListWithFirstScreenUnSelectable> {
+    private ListView mListView;
+
+    public ListWithFirstScreenUnSelectableTest() {
+        super("com.android.frameworktest", ListWithFirstScreenUnSelectable.class);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        setActivityInitialTouchMode(true);
+
+        mListView = getActivity().getListView();
+    }
+
+    public void testPreconditions() {
+        assertTrue(mListView.isInTouchMode());
+        assertEquals(1, mListView.getChildCount());
+        assertFalse(mListView.getAdapter().isEnabled(0));
+        assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+    }
+    
+    public void testRessurectSelection() {
+        sendKeys(KeyEvent.KEYCODE_SPACE);
+        assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+    }
+
+    public void testScrollUpDoesNothing() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+        assertEquals(1, mListView.getChildCount());
+        assertEquals(0, mListView.getFirstVisiblePosition());
+    }
+
+    public void testScrollDownPansNextItemOn() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(2, mListView.getChildCount());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithNoFadingEdgeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithNoFadingEdgeTest.java
new file mode 100644
index 0000000..449e048
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithNoFadingEdgeTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview.arrowscroll;
+
+import com.android.frameworktest.listview.ListWithNoFadingEdge;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+
+public class ListWithNoFadingEdgeTest extends ActivityInstrumentationTestCase<ListWithNoFadingEdge> {
+
+    private ListView mListView;
+
+    public ListWithNoFadingEdgeTest() {
+        super("com.android.frameworktest", ListWithNoFadingEdge.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mListView);
+        assertEquals("listview vertical fading edge", 0, mListView.getVerticalFadingEdgeLength());
+        assertTrue("expecting that not all views fit on screen",
+                mListView.getChildCount() < mListView.getCount());
+    }
+
+    @MediumTest
+    public void testScrollDownToBottom() {
+        final int numItems = mListView.getCount();
+
+        for (int i = 0; i < numItems; i++) {
+            assertEquals("selected position", i, mListView.getSelectedItemPosition());
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals("selected position", numItems - 1, mListView.getSelectedItemPosition());            
+    }
+
+    @LargeTest
+    public void testScrollFromBottomToTop() {
+        final int numItems = mListView.getCount();
+
+        getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setSelection(numItems - 1);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        for (int i = numItems - 1; i >=0; i--) {
+            assertEquals(i, mListView.getSelectedItemPosition());
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        }
+
+        assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
new file mode 100644
index 0000000..6e62ccb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.android.frameworktest.listview.ListWithOffScreenNextSelectable;
+
+public class ListWithOffScreenNextSelectableTest
+        extends ActivityInstrumentationTestCase<ListWithOffScreenNextSelectable> {
+    private ListView mListView;
+
+    public ListWithOffScreenNextSelectableTest() {
+        super("com.android.frameworktest", ListWithOffScreenNextSelectable.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mListView);
+        assertEquals(5, mListView.getAdapter().getCount());
+        assertFalse(mListView.getAdapter().areAllItemsEnabled());
+        assertFalse(mListView.getAdapter().isEnabled(1));
+        assertFalse(mListView.getAdapter().isEnabled(2));
+        assertFalse(mListView.getAdapter().isEnabled(3));
+        assertEquals("only 4 children should be on screen (so that next selectable is off " +
+                "screen) for this test to be meaningful.",
+                4, mListView.getChildCount());
+        assertEquals(0, mListView.getSelectedItemPosition());
+    }
+
+    // when the next items on screen are not selectable, we pan until the next selectable item
+    // is (partially visible), then we jump to it
+    @MediumTest
+    public void testGoDownToOffScreenSelectable() {
+
+        final int listBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+
+        final View lastVisibleView = mListView.getChildAt(mListView.getChildCount() - 1);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("expecting view to be panned to just above fading edge",
+                listBottom - mListView.getVerticalFadingEdgeLength(), lastVisibleView.getBottom());
+        assertEquals("selection should not have moved yet",
+                0, mListView.getSelectedItemPosition());
+        
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("selection should have moved",
+                4, mListView.getSelectedItemPosition());
+        assertEquals("wrong view created when scrolling",
+                getActivity().getValueAtPosition(4), ((TextView) mListView.getSelectedView()).getText());
+        assertEquals(listBottom, mListView.getSelectedView().getBottom());
+    }
+
+    @MediumTest
+    public void testGoUpToOffScreenSelectable() {
+        final int listBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+        final int listTop = mListView.getListPaddingTop();
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals(4, mListView.getSelectedItemPosition());
+        assertEquals(listBottom, mListView.getSelectedView().getBottom());
+
+        // now we have the reverse situation: the next selectable position upward is off screen
+        final View firstVisibleView = mListView.getChildAt(0);
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("should have panned top view just below vertical fading edge",
+                listTop + mListView.getVerticalFadingEdgeLength(), firstVisibleView.getTop());
+        assertEquals("selection should not have moved yet",
+                4, mListView.getSelectedItemPosition());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("selection should have moved",
+                0, mListView.getSelectedItemPosition());
+        assertEquals(getActivity().getValueAtPosition(0),((TextView) mListView.getSelectedView()).getText());
+        assertEquals(listTop, mListView.getSelectedView().getTop());
+
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOnItemSelectedActionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
new file mode 100644
index 0000000..0a8af45
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListWithOnItemSelectedAction;
+
+public class ListWithOnItemSelectedActionTest extends ActivityInstrumentationTestCase<ListWithOnItemSelectedAction> {
+    private ListView mListView;
+
+    public ListWithOnItemSelectedActionTest() {
+        super("com.android.frameworktest", ListWithOnItemSelectedAction.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mListView = getActivity().getListView();
+    }
+
+    private String getValueOfSelectedTextView() {
+        return ((TextView) mListView.getSelectedView()).getText().toString();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertEquals(0, mListView.getSelectedItemPosition());
+        assertEquals("header text field should be echoing contents of selected item",
+                getValueOfSelectedTextView(),
+                getActivity().getHeaderValue());
+    }
+
+    @MediumTest
+    public void testHeaderEchoesSelectionAfterMove() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals(1, mListView.getSelectedItemPosition());
+        assertEquals("header text field should be echoing contents of selected item",
+                getValueOfSelectedTextView(),
+                getActivity().getHeaderValue());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
new file mode 100644
index 0000000..0c0084e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview.arrowscroll;
+
+import com.android.frameworktest.listview.ListWithScreenOfNoSelectables;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+
+public class ListWithScreenOfNoSelectablesTest extends ActivityInstrumentationTestCase<ListWithScreenOfNoSelectables> {
+
+    private ListView mListView;
+
+    public ListWithScreenOfNoSelectablesTest() {
+        super("com.android.frameworktest", ListWithScreenOfNoSelectables.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("expecting first position to be selectable",
+                mListView.getAdapter().isEnabled(0));
+        final int numItems = mListView.getCount();
+        for (int i = 1; i < numItems; i++) {
+            assertFalse("expecting item to be unselectable (index " + i +")",
+                    mListView.getAdapter().isEnabled(i));
+        }
+        assertTrue("expecting that not all views fit on screen",
+                mListView.getChildCount() < mListView.getCount());
+    }
+
+
+    @MediumTest
+    public void testGoFromSelectedViewExistsToNoSelectedViewExists() {
+
+        // go down untile first (and only selectable) item is off screen
+        View first = mListView.getChildAt(0);
+        while (first.getParent() != null) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        // nothing should be selected
+        assertEquals("selected position", ListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+        assertNull("selected view", mListView.getSelectedView());
+    }
+
+    @LargeTest
+    public void testPanDownAcrossUnselectableChildrenToBottom() {
+        final int lastPosition = mListView.getCount() - 1;
+        final int maxDowns = 20;
+        for(int count = 0; count < maxDowns && mListView.getLastVisiblePosition() <= lastPosition; count++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        assertEquals("last visible position not the last position in the list even "
+                + "after " + maxDowns + " downs", lastPosition, mListView.getLastVisiblePosition());
+    }
+
+    @MediumTest
+    public void testGoFromNoSelectionToSelectionExists() {
+        // go down untile first (and only selectable) item is off screen
+        View first = mListView.getChildAt(0);
+        while (first.getParent() != null) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        // nothing should be selected
+        assertEquals("selected position", ListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+        assertNull("selected view", mListView.getSelectedView());
+
+        // go up once to bring the selectable back on screen
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("first visible position", 0, mListView.getFirstVisiblePosition());
+        assertEquals("selected position", ListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+
+
+        // up once more should give it selection
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+
+    }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithSeparatorsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithSeparatorsTest.java
new file mode 100644
index 0000000..fdeaa4a
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithSeparatorsTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListWithSeparators;
+
+public class ListWithSeparatorsTest extends ActivityInstrumentationTestCase<ListWithSeparators> {
+    private ListWithSeparators mActivity;
+    private ListView mListView;
+
+    public ListWithSeparatorsTest() {
+        super("com.android.frameworktest", ListWithSeparators.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        assertFalse(mListView.getAdapter().areAllItemsEnabled());
+        assertFalse(mListView.getAdapter().isEnabled(0));
+        assertFalse(mListView.getAdapter().isEnabled(2));
+        assertEquals(1, mListView.getSelectedItemPosition());
+    }
+
+    @MediumTest
+    public void testGoingUpDoesnNotHitUnselectableItem() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals("selected position should remain the same",
+                1, mListView.getSelectedItemPosition());
+
+        assertEquals("seperator should be scrolled flush with top",
+                mListView.getListPaddingTop(), mListView.getChildAt(0).getTop());
+    }
+
+    @MediumTest
+    public void testGoingDownSkipsOverUnselectable() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("should have skipped to next selectable ",
+                3,
+                mListView.getSelectedItemPosition());
+    }
+        
+    @MediumTest
+    public void testGoingUpSkippingOverUnselectable() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertEquals(1, mListView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
new file mode 100644
index 0000000..2c0c2d8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview.focus;
+
+import com.android.frameworktest.listview.AdjacentListsWithAdjacentISVsInside;
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+
+public class AdjacentListsWithAdjacentISVsInsideTest extends ActivityInstrumentationTestCase<AdjacentListsWithAdjacentISVsInside> {
+
+    private ListView mLeftListView;
+    private InternalSelectionView mLeftIsv;
+    private InternalSelectionView mLeftMiddleIsv;
+    private ListView mRightListView;
+    private InternalSelectionView mRightMiddleIsv;
+    private InternalSelectionView mRightIsv;
+
+    public AdjacentListsWithAdjacentISVsInsideTest() {
+        super("com.android.frameworktest", AdjacentListsWithAdjacentISVsInside.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final AdjacentListsWithAdjacentISVsInside a = getActivity();
+        mLeftListView = a.getLeftListView();
+        mLeftIsv = a.getLeftIsv();
+        mLeftMiddleIsv = a.getLeftMiddleIsv();
+        mRightListView = a.getRightListView();
+        mRightMiddleIsv = a.getRightMiddleIsv();
+        mRightIsv = a.getRightIsv();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue(mLeftListView.hasFocus());
+        assertTrue(mLeftIsv.isFocused());
+        assertEquals(0, mLeftIsv.getSelectedRow());
+    }
+
+    /**
+     * rockinist test name to date!
+     */
+    @MediumTest
+    public void testFocusedRectAndFocusHintWorkWithinListItemHorizontal() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals(1, mLeftIsv.getSelectedRow());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        assertTrue(mLeftListView.hasFocus());
+        assertTrue(mLeftMiddleIsv.isFocused());
+        assertEquals("mLeftMiddleIsv.getSelectedRow()", 1, mLeftMiddleIsv.getSelectedRow());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+        assertTrue(mLeftIsv.isFocused());
+        assertEquals("mLeftIsv.getSelectedRow()", 1, mLeftIsv.getSelectedRow());
+    }
+
+    @MediumTest
+    public void testFocusTransfersOutsideOfListWhenNoCandidateInsideHorizontal() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
+
+        assertTrue(mLeftListView.hasFocus());
+        assertTrue(mLeftMiddleIsv.isFocused());
+        assertEquals(2, mLeftMiddleIsv.getSelectedRow());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        assertTrue("mRightListView.hasFocus()", mRightListView.hasFocus());
+        assertTrue("mRightMiddleIsv.isFocused()", mRightMiddleIsv.isFocused());
+        assertEquals("mRightMiddleIsv.getSelectedRow()", 2, mRightMiddleIsv.getSelectedRow());  
+    }    
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListButtonsDiagonalAcrossItemsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
new file mode 100644
index 0000000..c54add3
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview.focus;
+
+import com.android.frameworktest.listview.ListButtonsDiagonalAcrossItems;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.FocusFinder;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ListView;
+
+/**
+ * Test that ListView will override default behavior of focus searching to
+ * make sure going right and left doesn't change selection
+ */
+public class ListButtonsDiagonalAcrossItemsTest extends ActivityInstrumentationTestCase<ListButtonsDiagonalAcrossItems> {
+
+    private Button mLeftButton;
+    private Button mCenterButton;
+    private Button mRightButton;
+    private ListView mListView;
+
+    public ListButtonsDiagonalAcrossItemsTest() {
+        super("com.android.frameworktest", ListButtonsDiagonalAcrossItems.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mLeftButton = getActivity().getLeftButton();
+        mCenterButton = getActivity().getCenterButton();
+        mRightButton = getActivity().getRightButton();
+
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        final ListView lv = mListView;
+        assertEquals("num children", 3, lv.getChildCount());
+
+        assertEquals("selected position", 0, lv.getSelectedItemPosition());
+        assertTrue("left button focused", mLeftButton.isFocused());
+
+        assertTrue("left left of center",
+                mLeftButton.getRight()
+                        < mCenterButton.getLeft());
+
+        assertTrue("center left of right",
+                mCenterButton.getRight()
+                        < mRightButton.getLeft());
+
+        assertEquals("focus search right from left button should be center button",
+            mCenterButton,
+            FocusFinder.getInstance().findNextFocus(mListView, mLeftButton, View.FOCUS_RIGHT));
+        assertEquals("focus search right from center button should be right button",
+            mRightButton,
+            FocusFinder.getInstance().findNextFocus(mListView, mCenterButton, View.FOCUS_RIGHT));
+        assertEquals("focus search left from centr button should be left button",
+            mLeftButton,
+            FocusFinder.getInstance().findNextFocus(mListView, mCenterButton, View.FOCUS_LEFT));
+    }
+
+    @MediumTest
+    public void testGoingRightDoesNotChangeSelection() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+
+        assertEquals("selected position shouldn't have changed",
+                0,
+                mListView.getSelectedItemPosition());
+        assertTrue("left should still be focused", mLeftButton.isFocused());
+    }
+
+    @MediumTest
+    public void testGoingLeftDoesNotChangeSelection() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("list view postion", 1, mListView.getSelectedItemPosition());
+        assertTrue("mCenterButton.isFocused()", mCenterButton.isFocused());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+        assertEquals("selected position shouldn't have changed",
+                1,
+                mListView.getSelectedItemPosition());
+        assertTrue("center should still be focused", mCenterButton.isFocused());
+    }
+    
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListHorizontalFocusWithinItemWinsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
new file mode 100644
index 0000000..35f9b06
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview.focus;
+
+import com.android.frameworktest.listview.ListHorizontalFocusWithinItemWins;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.FocusFinder;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ListView;
+
+public class ListHorizontalFocusWithinItemWinsTest extends ActivityInstrumentationTestCase<ListHorizontalFocusWithinItemWins> {
+
+    private ListView mListView;
+    private Button mTopLeftButton;
+    private Button mTopRightButton;
+    private Button mBottomMiddleButton;
+
+    public ListHorizontalFocusWithinItemWinsTest() {
+        super("com.android.frameworktest", ListHorizontalFocusWithinItemWins.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mListView = getActivity().getListView();
+        mTopLeftButton = getActivity().getTopLeftButton();
+        mTopRightButton = getActivity().getTopRightButton();
+        mBottomMiddleButton = getActivity().getBottomMiddleButton();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertEquals("list position", 0, mListView.getSelectedItemPosition());
+        assertTrue("mTopLeftButton.isFocused()", mTopLeftButton.isFocused());
+        assertEquals("global focus search to right from top left is bottom middle",
+                mBottomMiddleButton,
+                FocusFinder.getInstance().findNextFocus(mListView, mTopLeftButton, View.FOCUS_RIGHT));
+        assertEquals("global focus search to left from top right is bottom middle",
+                mBottomMiddleButton,
+                FocusFinder.getInstance().findNextFocus(mListView, mTopRightButton, View.FOCUS_LEFT));
+    }
+
+    @MediumTest
+    public void testOptionWithinItemTrumpsGlobal() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+
+        assertEquals("list position", 0, mListView.getSelectedItemPosition());
+        assertTrue("mTopRightButton.isFocused()", mTopRightButton.isFocused());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+        assertEquals("list position", 0, mListView.getSelectedItemPosition());
+        assertTrue("mTopLeftButton.isFocused()", mTopLeftButton.isFocused());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListWithEditTextHeaderTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListWithEditTextHeaderTest.java
new file mode 100644
index 0000000..dea689f
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListWithEditTextHeaderTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.listview.focus;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.KeyEvent;
+import android.widget.AbsListView;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListWithEditTextHeader;
+
+public class ListWithEditTextHeaderTest extends ActivityInstrumentationTestCase<ListWithEditTextHeader> {
+    private ListView mListView;
+
+    public ListWithEditTextHeaderTest() {
+        super("com.android.frameworktest", ListWithEditTextHeader.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("listview.getItemsCanFocus()", mListView.getItemsCanFocus());
+        assertFalse("out of touch-mode", mListView.isInTouchMode());
+        assertEquals("header view count", 1, mListView.getHeaderViewsCount());
+        assertTrue("header has focus", mListView.getChildAt(0).isFocused());
+    }
+
+    @FlakyTest(tolerance=2)
+    @LargeTest
+    public void testClickingHeaderKeepsFocus() {
+        TouchUtils.clickView(this, mListView.getChildAt(0));
+        assertTrue("header has focus", mListView.getChildAt(0).isFocused());
+        assertEquals("nothing selected", AbsListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+    }
+
+    @LargeTest
+    public void testClickingHeaderWhenOtherItemHasFocusGivesHeaderFocus() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertEquals("selected position", 1, mListView.getSelectedItemPosition());
+        TouchUtils.clickView(this, mListView.getChildAt(0));
+        assertTrue("header has focus", mListView.getChildAt(0).isFocused());        
+        assertEquals("nothing selected", AbsListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListGetSelectedViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListGetSelectedViewTest.java
new file mode 100644
index 0000000..3a75f93
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListGetSelectedViewTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.widget.ListView;
+import android.view.View;
+
+import com.android.frameworktest.listview.ListGetSelectedView;
+
+/**
+ * This test is made to check that getSelectedView() will return
+ * null in touch mode.
+ */
+public class ListGetSelectedViewTest extends ActivityInstrumentationTestCase<ListGetSelectedView> {
+    private ListGetSelectedView mActivity;
+    private ListView mListView;
+
+    public ListGetSelectedViewTest() {
+        super("com.android.frameworktest", ListGetSelectedView.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+
+        assertEquals(0, mListView.getSelectedItemPosition());
+    }
+
+    @LargeTest
+    public void testGetSelectedView() {
+        View last = mListView.getChildAt(1);
+        TouchUtils.clickView(this, last);
+
+        assertNull(mListView.getSelectedItem());
+        assertNull(mListView.getSelectedView());
+        assertEquals(-1, mListView.getSelectedItemPosition());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListOfTouchablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListOfTouchablesTest.java
new file mode 100644
index 0000000..f8b384d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListOfTouchablesTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListOfTouchables;
+import android.test.TouchUtils;
+
+/**
+ * Touch tests for a list where all of the items fit on the screen.
+ */
+public class ListOfTouchablesTest extends ActivityInstrumentationTestCase<ListOfTouchables> {
+    private ListOfTouchables mActivity;
+    private ListView mListView;
+
+    public ListOfTouchablesTest() {
+        super("com.android.frameworktest", ListOfTouchables.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+    }
+    
+    @LargeTest
+    public void testShortScroll() {
+        View firstChild = mListView.getChildAt(0);
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        int firstTop = firstChild.getTop();
+        
+        TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT,
+                0, -(ViewConfiguration.getTouchSlop() + 1 + 10));
+        
+        View newFirstChild = mListView.getChildAt(0);
+        
+        assertEquals("View scrolled too early", firstTop, newFirstChild.getTop() + 10);
+        assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+    }
+    
+    @LargeTest
+    public void testLongScroll() {
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        int lastTop = lastChild.getTop();
+        
+        int distance = TouchUtils.dragViewToY(this, lastChild, 
+                Gravity.TOP | Gravity.LEFT, mListView.getTop());
+        
+        assertEquals("View scrolled to wrong position", 
+                lastTop - (distance - ViewConfiguration.getTouchSlop() - 1), lastChild.getTop());
+    } 
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListSetSelectionTest.java
new file mode 100644
index 0000000..c3d7264
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListSetSelectionTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListSimple;
+
+/**
+ * Tests setting the selection in touch mode
+ */
+public class ListSetSelectionTest extends ActivityInstrumentationTestCase<ListSimple> {
+    private ListSimple mActivity;
+    private ListView mListView;
+
+    public ListSetSelectionTest() {
+        super("com.android.frameworktest", ListSimple.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+    }
+    
+    @LargeTest
+    public void testSetSelection() {
+        TouchUtils.dragQuarterScreenDown(this);
+        TouchUtils.dragQuarterScreenUp(this);
+        
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+        
+        final int targetPosition = mListView.getAdapter().getCount() / 2;
+        
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setSelection(targetPosition);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        
+        boolean found = false;
+        int childCount = mListView.getChildCount();
+        for (int i=0; i<childCount; i++) {
+            View child = mListView.getChildAt(i);
+            if (child.getId() == targetPosition) {
+                found = true;
+                break;
+            }
+        }
+        assertTrue("Selected item not visible in list", found);
+    }
+ 
+    @LargeTest
+    public void testSetSelectionFromTop() {
+        TouchUtils.dragQuarterScreenDown(this);
+        TouchUtils.dragQuarterScreenUp(this);
+        
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+        
+        final int targetPosition = mListView.getAdapter().getCount() / 2;
+        
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setSelectionFromTop(targetPosition, 100);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        
+        View target = null;
+        boolean found = false;
+        int childCount = mListView.getChildCount();
+        for (int i=0; i<childCount; i++) {
+            View child = mListView.getChildAt(i);
+            if (child.getId() == targetPosition) {
+                target = child;
+                found = true;
+                break;
+            }
+        }
+        assertTrue("Selected item not visible in list", found);
+        
+        if (target != null) {
+            assertEquals("Selection not at correct location", 100 + mListView.getPaddingTop(), 
+                    target.getTop());
+        }
+    }
+
+    @LargeTest
+    public void testSetSelection0() {
+        TouchUtils.dragQuarterScreenDown(this);
+        TouchUtils.dragQuarterScreenDown(this);
+        TouchUtils.dragQuarterScreenDown(this);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1,
+                mListView.getSelectedItemPosition());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mListView.setSelection(0);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        boolean found = false;
+        int childCount = mListView.getChildCount();
+        for (int i=0; i<childCount; i++) {
+            View child = mListView.getChildAt(i);
+            if (child.getId() == 0 && i == 0) {
+                found = true;
+                break;
+            }
+        }
+        assertTrue("Selected item not visible in list", found);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityManyTest.java
new file mode 100644
index 0000000..d271564
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityManyTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListBottomGravityMany;
+
+/**
+ * Touch tests for a list where all of the items do not fit on the screen, and the list 
+ * stacks from the bottom.
+ */
+public class ListTouchBottomGravityManyTest extends ActivityInstrumentationTestCase<ListBottomGravityMany> {
+    private ListBottomGravityMany mActivity;
+    private ListView mListView;
+
+    public ListTouchBottomGravityManyTest() {
+        super("com.android.frameworktest", ListBottomGravityMany.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        // Last item should be selected
+        assertEquals(mListView.getAdapter().getCount() - 1, mListView.getSelectedItemPosition());
+    }
+    
+    @LargeTest
+    public void testPullDown() {     
+        int originalCount = mListView.getChildCount();
+        
+        TouchUtils.scrollToTop(this, mListView);
+        
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+        
+        View firstChild = mListView.getChildAt(0);
+        
+        assertEquals("Item zero not the first child in the list", 0, firstChild.getId());
+        
+        assertEquals("Item zero not at the top of the list", mListView.getListPaddingTop(),
+                firstChild.getTop());
+        
+        assertTrue(String.format("Too many children created: %d expected no more than %d", 
+                mListView.getChildCount(), originalCount + 1), 
+                mListView.getChildCount() <= originalCount + 1);
+    }
+    
+    @MediumTest
+    public void testPushUp() {
+        TouchUtils.scrollToBottom(this, mListView);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+        assertEquals("List is not scrolled to the bottom", mListView.getAdapter().getCount() - 1,
+                lastChild.getId());
+
+        assertEquals("Last item is not touching the bottom edge", 
+                mListView.getHeight() - mListView.getListPaddingBottom(), lastChild.getBottom());
+    }
+    
+    @MediumTest
+    public void testNoScroll() {
+        View firstChild = mListView.getChildAt(0);
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        int lastTop = lastChild.getTop();
+        
+        TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
+                0, ViewConfiguration.getTouchSlop());
+        
+        View newLastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        assertEquals("View scrolled too early", lastTop, newLastChild.getTop());
+        assertEquals("Wrong view in last position", mListView.getAdapter().getCount() - 1, 
+                newLastChild.getId());
+    }
+    
+    @LargeTest
+    public void testShortScroll() {
+        View firstChild = mListView.getChildAt(0);
+        if (firstChild.getTop() < this.mListView.getListPaddingTop()) {
+            firstChild = mListView.getChildAt(1);
+        }
+            
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        int lastTop = lastChild.getTop();
+        
+        TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
+                0, ViewConfiguration.getTouchSlop() + 1 + 10);
+        
+        View newLastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        assertEquals("View scrolled to wrong position", lastTop, newLastChild.getTop() - 10);
+        assertEquals("Wrong view in last position", mListView.getAdapter().getCount() - 1,
+                newLastChild.getId());
+    }
+    
+    @LargeTest
+    public void testLongScroll() {
+        View firstChild = mListView.getChildAt(0);
+        if (firstChild.getTop() < mListView.getListPaddingTop()) {
+            firstChild = mListView.getChildAt(1);
+        }
+
+        int firstTop = firstChild.getTop();
+
+        int distance = TouchUtils.dragViewBy(this, firstChild, 
+                Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 
+                (int)(mActivity.getWindowManager().getDefaultDisplay().getHeight() * 0.75f));
+        
+        assertEquals("View scrolled to wrong position", firstTop
+                + (distance - ViewConfiguration.getTouchSlop() - 1), firstChild.getTop());
+    } 
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityTest.java
new file mode 100644
index 0000000..78d39fb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListBottomGravity;
+
+/**
+ * Touch tests for a list where all of the items fit on the screen, and the list 
+ * stacks from the bottom.
+ */
+public class ListTouchBottomGravityTest extends ActivityInstrumentationTestCase<ListBottomGravity> {
+    private ListBottomGravity mActivity;
+    private ListView mListView;
+
+    public ListTouchBottomGravityTest() {
+        super("com.android.frameworktest", ListBottomGravity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        // First item should be selected
+        assertEquals(mListView.getAdapter().getCount() - 1, mListView.getSelectedItemPosition());
+    }
+    
+    @MediumTest
+    public void testPullDown() {
+        View firstChild = mListView.getChildAt(0);
+        
+        TouchUtils.dragViewToBottom(this, firstChild);
+        
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+        
+        assertEquals("List is not scrolled to the bottom", mListView.getAdapter().getCount() - 1,
+                lastChild.getId());
+
+        assertEquals("Last item is not touching the bottom edge", 
+                mListView.getHeight() - mListView.getListPaddingBottom(), lastChild.getBottom());
+    }
+    
+    @MediumTest
+    public void testPushUp() {
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        TouchUtils.dragViewToTop(this, lastChild);
+
+        lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+        
+        assertEquals("List is not scrolled to the bottom", mListView.getAdapter().getCount() - 1,
+                lastChild.getId());
+
+        assertEquals("Last item is not touching the bottom edge",  
+                mListView.getHeight() - mListView.getListPaddingBottom(), lastChild.getBottom());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchManyTest.java
new file mode 100644
index 0000000..ef085f8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchManyTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListTopGravityMany;
+
+/**
+ * Touch tests for a list where all of the items do not fit on the screen.
+ */
+public class ListTouchManyTest extends ActivityInstrumentationTestCase<ListTopGravityMany> {
+    private ListTopGravityMany mActivity;
+    private ListView mListView;
+
+    public ListTouchManyTest() {
+        super("com.android.frameworktest", ListTopGravityMany.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        // First item should be selected
+        assertEquals(0, mListView.getSelectedItemPosition());
+    }
+    
+    @MediumTest
+    public void testPullDown() {
+        TouchUtils.scrollToTop(this, mListView);
+        
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+        
+        View firstChild = mListView.getChildAt(0);
+        
+        assertEquals("Item zero not the first child in the list", 0, firstChild.getId());
+        
+        assertEquals("Item zero not at the top of the list", mListView.getListPaddingTop(),
+                firstChild.getTop());
+    }
+    
+    @LargeTest
+    public void testPushUp() {
+        int originalCount = mListView.getChildCount();
+        
+        TouchUtils.scrollToBottom(this, mListView);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+        assertEquals("List is not scrolled to the bottom", mListView.getAdapter().getCount() - 1,
+                lastChild.getId());
+
+        assertEquals("Last item is not touching the bottom edge",  
+                mListView.getHeight() - mListView.getListPaddingBottom(), lastChild.getBottom());
+        
+        assertTrue(String.format("Too many children created: %d expected no more than %d", 
+                mListView.getChildCount(), originalCount + 1), 
+                mListView.getChildCount() <= originalCount + 1);
+    }
+
+    @LargeTest
+    public void testPress() {
+        int i;
+        int count = mListView.getChildCount();
+        mActivity.setClickedPosition(-1);
+        mActivity.setLongClickedPosition(-1);
+        
+        for (i = 0; i < count; i++) {
+            View child = mListView.getChildAt(i);
+            if ((child.getTop() >= mListView.getListPaddingTop())
+                    && (child.getBottom() <= 
+                        mListView.getHeight() - mListView.getListPaddingBottom())) {
+                TouchUtils.clickView(this, child);
+                
+                assertEquals("Incorrect view position reported being clicked", i, 
+                        mActivity.getClickedPosition());
+                assertEquals("View falsely reported being long clicked", -1, 
+                        mActivity.getLongClickedPosition());
+                try {
+                    Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.25f));
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+    
+    @LargeTest
+    public void testLongPress() {
+        int i;
+        int count = mListView.getChildCount();
+        mActivity.enableLongPress();
+        mActivity.setClickedPosition(-1);
+        mActivity.setLongClickedPosition(-1);
+        
+        for (i = 0; i < count; i++) {
+            View child = mListView.getChildAt(i);
+            if ((child.getTop() >= mListView.getListPaddingTop())
+                    && (child.getBottom() <= 
+                        mListView.getHeight() - mListView.getListPaddingBottom())) {
+                TouchUtils.longClickView(this, child);
+                assertEquals("Incorrect view position reported being long clicked", i, 
+                        mActivity.getLongClickedPosition());
+                assertEquals("View falsely reported being clicked", -1, 
+                        mActivity.getClickedPosition());
+            }
+        }
+    }
+    
+    @MediumTest
+    public void testNoScroll() {
+        View firstChild = mListView.getChildAt(0);
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        int firstTop = firstChild.getTop();
+        
+        TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT, 
+                0, -(ViewConfiguration.getTouchSlop()));
+        
+        View newFirstChild = mListView.getChildAt(0);
+        
+        assertEquals("View scrolled too early", firstTop, newFirstChild.getTop());
+        assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+    }
+    
+    @LargeTest
+    public void testShortScroll() {
+        View firstChild = mListView.getChildAt(0);
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        int firstTop = firstChild.getTop();
+        
+        TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT,
+                0, -(ViewConfiguration.getTouchSlop() + 1 + 10));
+        
+        View newFirstChild = mListView.getChildAt(0);
+        
+        assertEquals("View scrolled too early", firstTop, newFirstChild.getTop() + 10);
+        assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+    }
+    
+    @LargeTest
+    public void testLongScroll() {
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        int lastTop = lastChild.getTop();
+        
+        int distance = TouchUtils.dragViewToY(this, lastChild, 
+                Gravity.TOP | Gravity.LEFT, mListView.getTop());
+        
+        assertEquals("View scrolled to wrong position", 
+                lastTop - (distance - ViewConfiguration.getTouchSlop() - 1), lastChild.getTop());
+    } 
+
+    
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchTest.java
new file mode 100644
index 0000000..4e5c423
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListTopGravity;
+
+/**
+ * Touch tests for a list where all of the items fit on the screen.
+ */
+public class ListTouchTest extends ActivityInstrumentationTestCase<ListTopGravity> {
+    private ListTopGravity mActivity;
+    private ListView mListView;
+
+    public ListTouchTest() {
+        super("com.android.frameworktest", ListTopGravity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mListView = getActivity().getListView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertNotNull(mListView);
+        
+        // First item should be selected
+        assertEquals(0, mListView.getSelectedItemPosition());
+    }
+    
+    @MediumTest
+    public void testPullDown() {
+        View firstChild = mListView.getChildAt(0);
+        
+        TouchUtils.dragViewToBottom(this, firstChild);
+        
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+        
+        firstChild = mListView.getChildAt(0);
+        
+        assertEquals("Item zero not the first child in the list", 0, firstChild.getId());
+        
+        assertEquals("Item zero not at the top of the list", mListView.getListPaddingTop(),
+                firstChild.getTop());
+    }
+    
+    @MediumTest
+    public void testPushUp() {
+        View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+        
+        TouchUtils.dragViewToTop(this, lastChild);
+
+        // Nothing should be selected
+        assertEquals("Selection still available after touch", -1, 
+                mListView.getSelectedItemPosition());
+
+        View firstChild = mListView.getChildAt(0);
+
+        assertEquals("Item zero not the first child in the list", 0, firstChild.getId());
+        
+        assertEquals("Item zero not at the top of the list", mListView.getListPaddingTop(),
+                firstChild.getTop());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutLandscapeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutLandscapeTest.java
new file mode 100644
index 0000000..38cb6a1
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutLandscapeTest.java
@@ -0,0 +1,230 @@
+/**
+ * Copyright (C) 2008 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.frameworktest.menus;
+
+import com.android.frameworktest.util.KeyUtils;
+import com.android.internal.view.menu.IconMenuView;
+import com.android.internal.view.menu.MenuBuilder;
+
+import android.content.pm.ActivityInfo;
+import android.test.ActivityInstrumentationTestCase;
+
+public class MenuLayoutLandscapeTest extends ActivityInstrumentationTestCase<MenuLayoutLandscape> {
+    private static final String LONG_TITLE = "Really really really really really really really really really really long title";
+    private static final String SHORT_TITLE = "Item";
+
+    private MenuLayout mActivity;
+    
+    public MenuLayoutLandscapeTest() {
+        super("com.android.frameworktest", MenuLayoutLandscape.class);
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+    }
+
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+    }
+
+    private void toggleMenu() {
+        getInstrumentation().waitForIdleSync();
+        KeyUtils.tapMenuKey(this);
+        getInstrumentation().waitForIdleSync();
+    }
+
+    /**
+     * Asserts the layout of the menu.
+     * 
+     * @param expectedLayout The number of parameters is the number of rows, and
+     *            each parameter is how many items on that row (the first
+     *            parameter is the top-most row).
+     */
+    private void assertLayout(Integer... expectedLayout) {
+        toggleMenu();
+        
+        IconMenuView iconMenuView = ((IconMenuView) mActivity.getMenuView(MenuBuilder.TYPE_ICON));
+        int[] layout = iconMenuView.getLayout();
+        int layoutNumRows = iconMenuView.getLayoutNumRows(); 
+        
+        int expectedRows = expectedLayout.length;
+        assertEquals("Row mismatch", expectedRows, layoutNumRows);
+        
+        for (int row = 0; row < expectedRows; row++) {
+            assertEquals("Col mismatch on row " + row, expectedLayout[row].intValue(),
+                    layout[row]);
+        }
+    }
+    
+    public void test1ShortItem() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(1)
+                .setItemTitle(0, SHORT_TITLE));
+        assertLayout(1);
+    }
+
+    public void test1LongItem() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(1)
+                .setItemTitle(0, LONG_TITLE));
+        assertLayout(1);
+    }
+
+    public void test2LongItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(2)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, LONG_TITLE));
+        assertLayout(1, 1);
+    }
+
+    public void test2ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(2)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE));
+        assertLayout(2);
+    }
+
+    public void test3ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(3)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE));
+        assertLayout(3);
+    }
+    
+    public void test3VarietyItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(3)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, SHORT_TITLE));
+        assertLayout(1, 2);
+    }
+
+    public void test3VarietyItems2() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(3)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE));
+        assertLayout(1, 2);
+    }
+
+    public void test4LongItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(4)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, LONG_TITLE)
+                .setItemTitle(3, LONG_TITLE));
+        assertLayout(2, 2);
+    }
+
+    public void test4ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(4)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, SHORT_TITLE));
+        assertLayout(4);
+    }
+    
+    public void test4VarietyItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(4)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, SHORT_TITLE));
+        assertLayout(2, 2);
+    }
+
+    public void test5ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(5)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, SHORT_TITLE)
+                .setItemTitle(4, SHORT_TITLE));
+        assertLayout(5);
+    }
+
+    public void test5LongItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(5)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, LONG_TITLE)
+                .setItemTitle(3, LONG_TITLE)
+                .setItemTitle(4, LONG_TITLE));
+        assertLayout(2, 3);
+    }
+
+    public void test5VarietyItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(5)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, LONG_TITLE)
+                .setItemTitle(3, SHORT_TITLE)
+                .setItemTitle(4, LONG_TITLE));
+        assertLayout(2, 3);
+    }
+
+    public void test6LongItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(6)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, LONG_TITLE)
+                .setItemTitle(3, LONG_TITLE)
+                .setItemTitle(4, LONG_TITLE)
+                .setItemTitle(5, LONG_TITLE));
+        assertLayout(3, 3);
+    }
+
+    public void test6ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(6)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, SHORT_TITLE)
+                .setItemTitle(4, SHORT_TITLE)
+                .setItemTitle(5, SHORT_TITLE));
+        assertLayout(6);
+    }
+
+    public void test6VarietyItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(6)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, LONG_TITLE)
+                .setItemTitle(4, SHORT_TITLE)
+                .setItemTitle(5, SHORT_TITLE));
+        assertLayout(3, 3);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutPortraitTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutPortraitTest.java
new file mode 100644
index 0000000..a04ec62
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutPortraitTest.java
@@ -0,0 +1,231 @@
+/**
+ * Copyright (C) 2008 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.frameworktest.menus;
+
+import com.android.frameworktest.util.KeyUtils;
+import com.android.internal.view.menu.IconMenuView;
+import com.android.internal.view.menu.MenuBuilder;
+
+import android.content.pm.ActivityInfo;
+import android.test.ActivityInstrumentationTestCase;
+
+public class MenuLayoutPortraitTest extends ActivityInstrumentationTestCase<MenuLayoutPortrait> {
+    private static final String LONG_TITLE = "Really really really really really really really really really really long title";
+    private static final String SHORT_TITLE = "Item";
+
+    private MenuLayout mActivity;
+    
+    public MenuLayoutPortraitTest() {
+        super("com.android.frameworktest", MenuLayoutPortrait.class);
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+    }
+
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+    }
+
+    private void toggleMenu() {
+        getInstrumentation().waitForIdleSync();
+        KeyUtils.tapMenuKey(this);
+        getInstrumentation().waitForIdleSync();
+    }
+
+    /**
+     * Asserts the layout of the menu.
+     * 
+     * @param expectedLayout The number of parameters is the number of rows, and
+     *            each parameter is how many items on that row.
+     */
+    private void assertLayout(Integer... expectedLayout) {
+        toggleMenu();
+        
+        IconMenuView iconMenuView = ((IconMenuView) mActivity.getMenuView(MenuBuilder.TYPE_ICON));
+        int[] layout = iconMenuView.getLayout();
+        int layoutNumRows = iconMenuView.getLayoutNumRows(); 
+        
+        int expectedRows = expectedLayout.length;
+        assertEquals("Row mismatch", expectedRows, layoutNumRows);
+        
+        for (int row = 0; row < expectedRows; row++) {
+            assertEquals("Col mismatch on row " + row, expectedLayout[row].intValue(),
+                    layout[row]);
+        }
+    }
+    
+    public void test1ShortItem() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(1)
+                .setItemTitle(0, SHORT_TITLE));
+        assertLayout(1);
+    }
+
+    public void test1LongItem() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(1)
+                .setItemTitle(0, LONG_TITLE));
+        assertLayout(1);
+    }
+
+    public void test2LongItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(2)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, LONG_TITLE));
+        assertLayout(1, 1);
+    }
+
+    public void test2ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(2)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE));
+        assertLayout(2);
+    }
+
+    public void test3ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(3)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE));
+        assertLayout(3);
+    }
+    
+    public void test3VarietyItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(3)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, SHORT_TITLE));
+        // We maintain the order added, so there must be 3 rows
+        assertLayout(1, 1, 1);
+    }
+
+    public void test3VarietyItems2() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(3)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE));
+        // The long can fit in first row, and two shorts in second
+        assertLayout(1, 2);
+    }
+
+    public void test4LongItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(4)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, LONG_TITLE)
+                .setItemTitle(3, LONG_TITLE));
+        assertLayout(1, 1, 2);
+    }
+
+    public void test4ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(4)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, SHORT_TITLE));
+        assertLayout(2, 2);
+    }
+    
+    public void test4VarietyItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(4)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, SHORT_TITLE));
+        assertLayout(1, 1, 2);
+    }
+
+    public void test5ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(5)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, SHORT_TITLE)
+                .setItemTitle(4, SHORT_TITLE));
+        assertLayout(2, 3);
+    }
+
+    public void test5LongItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(5)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, LONG_TITLE)
+                .setItemTitle(3, LONG_TITLE)
+                .setItemTitle(4, LONG_TITLE));
+        assertLayout(1, 2, 2);
+    }
+
+    public void test5VarietyItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(5)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, LONG_TITLE)
+                .setItemTitle(3, SHORT_TITLE)
+                .setItemTitle(4, LONG_TITLE));
+        assertLayout(1, 2, 2);
+    }
+
+    public void test6LongItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(6)
+                .setItemTitle(0, LONG_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, LONG_TITLE)
+                .setItemTitle(3, LONG_TITLE)
+                .setItemTitle(4, LONG_TITLE)
+                .setItemTitle(5, LONG_TITLE));
+        assertLayout(2, 2, 2);
+    }
+
+    public void test6ShortItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(6)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, SHORT_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, SHORT_TITLE)
+                .setItemTitle(4, SHORT_TITLE)
+                .setItemTitle(5, SHORT_TITLE));
+        assertLayout(3, 3);
+    }
+
+    public void test6VarietyItems() {
+        mActivity.setParams(new MenuScenario.Params()
+                .setNumItems(6)
+                .setItemTitle(0, SHORT_TITLE)
+                .setItemTitle(1, LONG_TITLE)
+                .setItemTitle(2, SHORT_TITLE)
+                .setItemTitle(3, LONG_TITLE)
+                .setItemTitle(4, SHORT_TITLE)
+                .setItemTitle(5, SHORT_TITLE));
+        assertLayout(2, 2, 2);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuWith1ItemTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuWith1ItemTest.java
new file mode 100644
index 0000000..286533c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuWith1ItemTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.menus;
+
+import com.android.frameworktest.menus.MenuWith1Item;
+import com.android.frameworktest.util.KeyUtils;
+import com.android.internal.view.menu.MenuBuilder;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.view.KeyEvent;
+import android.view.View;
+
+public class MenuWith1ItemTest extends ActivityInstrumentationTestCase<MenuWith1Item> {
+    private MenuWith1Item mActivity;
+    
+    public MenuWith1ItemTest() {
+        super("com.android.frameworktest", MenuWith1Item.class);
+    }
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mActivity);
+        assertFalse(mActivity.getButton().isInTouchMode());
+    }
+
+    @MediumTest
+    public void testItemClick() {
+
+        // Open menu, click on an item
+        KeyUtils.tapMenuKey(this);
+        getInstrumentation().waitForIdleSync();
+        assertFalse("Item seems to have been clicked before we clicked on it", mActivity
+                .wasItemClicked(0));
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        assertTrue("Item doesn't seem to have registered our click", mActivity.wasItemClicked(0));
+    }
+
+    @LargeTest
+    public void testTouchModeTransfersRemovesFocus() throws Exception {
+        // open menu, move around to give it focus
+        sendKeys(KeyEvent.KEYCODE_MENU, KeyEvent.KEYCODE_DPAD_LEFT);
+        final View menuItem = mActivity.getItemView(MenuBuilder.TYPE_ICON, 0);
+        assertTrue("menuItem.isFocused()", menuItem.isFocused());
+
+        // close the menu
+        sendKeys(KeyEvent.KEYCODE_MENU);
+        Thread.sleep(500);
+
+        // touch the screen
+        TouchUtils.clickView(this, mActivity.getButton());
+        assertTrue("should be in touch mode after touching button",
+                mActivity.getButton().isInTouchMode());
+
+        // open the menu, menu item shouldn't be focused, because we are not
+        // in touch mode
+        sendKeys(KeyEvent.KEYCODE_MENU);
+        assertTrue("menuItem.isInTouchMode()", menuItem.isInTouchMode());
+        assertFalse("menuItem.isFocused()", menuItem.isFocused());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionViewTest.java
new file mode 100644
index 0000000..e4dd2b8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionViewTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.scroll;
+
+import com.android.frameworktest.scroll.ButtonAboveTallInternalSelectionView;
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+public class ButtonAboveTallInternalSelectionViewTest extends
+        ActivityInstrumentationTestCase<ButtonAboveTallInternalSelectionView> {
+
+    public ButtonAboveTallInternalSelectionViewTest() {
+        super("com.android.frameworktest", ButtonAboveTallInternalSelectionView.class);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("expecting the top button to have focus",
+                getActivity().getButtonAbove().isFocused());
+        assertEquals("scrollview scroll y",
+                0,
+                getActivity().getScrollView().getScrollY());
+        assertTrue("internal selection view should be taller than screen",
+                getActivity().getIsv().getHeight() > getActivity().getScrollView().getHeight());
+
+        assertTrue("top of ISV should be on screen",
+                getActivity().getIsv().getTop() >
+                getActivity().getScrollView().getScrollY());
+
+    }
+
+    @MediumTest
+    public void testMovingFocusDownToItemTallerThanScreenStillOnScreen() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        getInstrumentation().waitForIdleSync();
+
+        final InternalSelectionView isv = getActivity().getIsv();
+        assertTrue("internal selection view should have taken focus",
+                isv.isFocused());
+        assertEquals("internal selection view selected row",
+                0, isv.getSelectedRow());
+        assertTrue("top of ISV should still be on screen",
+                getActivity().getIsv().getTop() >
+                getActivity().getScrollView().getScrollY());
+    }
+
+    
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleTest.java
new file mode 100644
index 0000000..3eec37b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.scroll;
+
+import com.android.frameworktest.scroll.RequestRectangleVisible;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.view.View;
+import android.view.KeyEvent;
+
+/**
+ * {@link RequestRectangleVisible} is set up to exercise the cases of moving a
+ * rectangle that is either off screen or not entirely on the screen onto the screen.
+ */
+public class RequestRectangleVisibleTest extends ActivityInstrumentationTestCase<RequestRectangleVisible> {
+
+    private ScrollView mScrollView;
+
+    private Button mClickToScrollFromAbove;
+    private Button mClickToScrollToUpperBlob;
+    private TextView mTopBlob;
+
+    private View mChildToScrollTo;
+
+    private TextView mBottomBlob;
+    private Button mClickToScrollToBlobLowerBlob;
+    private Button mClickToScrollFromBelow;
+
+    public RequestRectangleVisibleTest() {
+        super("com.android.frameworktest", RequestRectangleVisible.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        RequestRectangleVisible a = getActivity();
+
+        mScrollView = (ScrollView) a.findViewById(R.id.scrollView);
+        mClickToScrollFromAbove = (Button) a.findViewById(R.id.scrollToRectFromTop);
+        mClickToScrollToUpperBlob = (Button) a.findViewById(R.id.scrollToRectFromTop2);
+        mTopBlob = (TextView) a.findViewById(R.id.topBlob);
+        mChildToScrollTo = a.findViewById(R.id.childToMakeVisible);
+        mBottomBlob = (TextView) a.findViewById(R.id.bottomBlob);
+        mClickToScrollToBlobLowerBlob = (Button) a.findViewById(R.id.scrollToRectFromBottom2);
+        mClickToScrollFromBelow = (Button) a.findViewById(R.id.scrollToRectFromBottom);
+
+        
+    }
+
+    
+    @MediumTest
+    public void testPreconditions() {
+        assertNotNull(mScrollView);
+        assertNotNull(mClickToScrollFromAbove);
+        assertNotNull(mClickToScrollToUpperBlob);
+        assertNotNull(mTopBlob);
+        assertNotNull(mChildToScrollTo);
+        assertNotNull(mBottomBlob);
+        assertNotNull(mClickToScrollToBlobLowerBlob);
+        assertNotNull(mClickToScrollFromBelow);
+
+        assertTrue("top blob needs to be taller than the screen for many of the "
+                + "tests below to work.",
+                mTopBlob.getHeight() > mScrollView.getHeight());
+
+        assertTrue("bottom blob needs to be taller than the screen for many of the "
+                + "tests below to work.",
+                mBottomBlob.getHeight() > mScrollView.getHeight());
+
+        assertTrue("top blob needs to be lower than the fading edge region",
+                mTopBlob.getTop() > mScrollView.getVerticalFadingEdgeLength());
+    }
+
+    @MediumTest
+    public void testScrollToOffScreenRectangleFromTop() {
+        // view is off screen
+        assertTrue(mClickToScrollFromAbove.hasFocus());
+        ViewAsserts.assertOffScreenBelow(mScrollView, mChildToScrollTo);
+
+        // click
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();  // wait for scrolling to finish
+
+        // should be on screen, positioned at the bottom (with room for
+        // fading edge)
+        ViewAsserts.assertOnScreen(mScrollView, mChildToScrollTo);
+        ViewAsserts.assertHasScreenCoordinates(
+                mScrollView, mChildToScrollTo,
+                0,
+                mScrollView.getHeight()
+                        - mChildToScrollTo.getHeight()
+                        - mScrollView.getVerticalFadingEdgeLength());
+    }
+
+    @MediumTest
+    public void testScrollToPartiallyOffScreenRectFromTop() {
+        pressDownUntilViewInFocus(mClickToScrollToUpperBlob, 4);
+
+        // make sure the blob is indeed partially on screen below
+        assertOnBottomEdgeOfScreen(mScrollView, mTopBlob);
+
+        // click
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();  // wait for scrolling to finish
+
+        // blob should have moved so top of it is at top of screen (with
+        // room for the vertical fading edge
+        ViewAsserts.assertHasScreenCoordinates(
+                mScrollView, mTopBlob, 0, mScrollView.getVerticalFadingEdgeLength());
+    }
+
+    @LargeTest
+    public void testScrollToOffScreenRectangleFromBottom() {
+        // go to bottom button
+        pressDownUntilViewInFocus(mClickToScrollFromBelow, 10);
+
+        // view is off screen above
+        assertTrue(mClickToScrollFromBelow.hasFocus());
+        ViewAsserts.assertOffScreenAbove(mScrollView, mChildToScrollTo);
+
+        // click
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();  // wait for scrolling to finish
+
+        // on screen, positioned at top (with room for fading edge)
+        ViewAsserts.assertOnScreen(mScrollView, mChildToScrollTo);
+        ViewAsserts.assertHasScreenCoordinates(
+                mScrollView, mChildToScrollTo, 0, mScrollView.getVerticalFadingEdgeLength());
+    }
+
+
+    @LargeTest
+    public void testScrollToPartiallyOffScreenRectFromBottom() {
+        pressDownUntilViewInFocus(mClickToScrollToBlobLowerBlob, 10);
+
+        // make sure the blob is indeed partially on screen above
+        assertOnTopEdgeOfScreen(mScrollView, mBottomBlob);
+
+        // click
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();  // wait for scrolling to finish
+
+        // blob should have moved so bottom of it is at bottom of screen
+        // with room for vertical fading edge
+        ViewAsserts.assertHasScreenCoordinates(
+                mScrollView, mBottomBlob,
+                0,
+                mScrollView.getHeight() - mBottomBlob.getHeight()
+                    - mScrollView.getVerticalFadingEdgeLength());
+    }
+
+
+    /**
+     * Press the down key until a particular view is in focus
+     * @param view The view to get in focus.
+     * @param maxKeyPress The maximum times to press down before failing.
+     */
+    private void pressDownUntilViewInFocus(View view, int maxKeyPress) {
+        int count = 0;
+        while(!view.hasFocus()) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+            getInstrumentation().waitForIdleSync();
+
+            // just in case...
+            if (++count > maxKeyPress) {
+                fail("couldn't move down to bottom button within "
+                        + maxKeyPress + " key presses.");
+            }
+        }
+    }
+
+    /**
+     * Assert that view overlaps the bottom edge of the screen
+     * @param origin The root view of the screen.
+     * @param view The view
+     */
+    static public void assertOnBottomEdgeOfScreen(View origin, View view) {
+        int[] xy = new int[2];
+        view.getLocationOnScreen(xy);
+
+        int[] xyRoot = new int[2];
+        origin.getLocationOnScreen(xyRoot);
+
+        int bottom = xy[1] + view.getHeight();
+        int bottomOfRoot = xyRoot[1] + origin.getHeight();
+
+        assertTrue(bottom > bottomOfRoot);
+
+        assertTrue(xy[1] < bottomOfRoot);
+        assertTrue(bottom > bottomOfRoot);
+    }
+
+    /**
+     * Assert that view overlaps the bottom edge of the screen
+     * @param origin The root view of the screen.
+     * @param view The view
+     */
+    static public void assertOnTopEdgeOfScreen(View origin, View view) {
+        int[] xy = new int[2];
+        view.getLocationOnScreen(xy);
+
+        int[] xyRoot = new int[2];
+        origin.getLocationOnScreen(xyRoot);
+
+        int bottom = xy[1] + view.getHeight();
+        int bottomOfRoot = xyRoot[1] + origin.getHeight();
+
+        assertTrue(bottom < bottomOfRoot);
+        assertTrue(bottom > xyRoot[1]);
+
+        assertTrue(xy[1] < xyRoot[1]);
+    }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScrollTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScrollTest.java
new file mode 100644
index 0000000..5d71466
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScrollTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.scroll;
+
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.ViewAsserts;
+import android.test.suitebuilder.annotation.Suppress;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+/**
+ * This is suppressed because {@link TextView#scrollBy} isn't working.
+ */
+@Suppress
+public class RequestRectangleVisibleWithInternalScrollTest
+        extends ActivityInstrumentationTestCase<RequestRectangleVisibleWithInternalScroll> {
+
+    private TextView mTextBlob;
+    private Button mScrollToBlob;
+
+    private ScrollView mScrollView;
+
+
+    public RequestRectangleVisibleWithInternalScrollTest() {
+        super("com.android.frameworktest",
+                RequestRectangleVisibleWithInternalScroll.class);
+    }
+
+    
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTextBlob = getActivity().getTextBlob();
+        mScrollToBlob = getActivity().getScrollToBlob();
+
+        mScrollView = (ScrollView) getActivity().findViewById(R.id.scrollView);
+    }
+
+    public void testPreconditions() {
+        assertNotNull(mTextBlob);
+        assertNotNull(mScrollToBlob);
+        assertEquals(getActivity().getScrollYofBlob(), mTextBlob.getScrollY());
+    }
+
+    public void testMoveToChildWithScrollYBelow() {
+        assertTrue(mScrollToBlob.hasFocus());
+
+        ViewAsserts.assertOffScreenBelow(mScrollView, mTextBlob);
+
+        // click
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();  // wait for scrolling to finish
+
+        // should be on screen, positioned at the bottom (with enough room for
+        // fading edge)
+        ViewAsserts.assertOnScreen(mScrollView, mTextBlob);
+        ViewAsserts.assertHasScreenCoordinates(
+                mScrollView, mTextBlob,
+                0,
+                mScrollView.getHeight()
+                        - mTextBlob.getHeight()
+                        - mScrollView.getVerticalFadingEdgeLength());
+
+    }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabelsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabelsTest.java
new file mode 100644
index 0000000..b23b567
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabelsTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.scroll;
+
+import com.android.frameworktest.scroll.ScrollViewButtonsAndLabels;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.view.KeyEvent;
+
+
+public class ScrollViewButtonsAndLabelsTest
+        extends ActivityInstrumentationTestCase<ScrollViewButtonsAndLabels> {
+
+    private ScrollView mScrollView;
+    private LinearLayout mLinearLayout;
+    private int mScreenBottom;
+    private int mScreenTop;
+
+    public ScrollViewButtonsAndLabelsTest() {
+        super("com.android.frameworktest",
+              ScrollViewButtonsAndLabels.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mScrollView = getActivity().getScrollView();
+        mLinearLayout = getActivity().getLinearLayout();
+
+        int origin[] = {0, 0};
+        mScrollView.getLocationOnScreen(origin);
+        mScreenTop = origin[1];
+        mScreenBottom = origin[1] + mScrollView.getHeight();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("vertical fading edge width needs to be non-zero for this "
+                + "test to be worth anything",
+                mScrollView.getVerticalFadingEdgeLength() > 0);
+    }
+
+    // moving down to something off screen should move the element
+    // onto the screen just above the vertical fading edge
+    @LargeTest
+    public void testArrowScrollDownOffScreenVerticalFadingEdge() {
+
+        int offScreenIndex = findFirstButtonOffScreenTop2Bottom();
+        Button firstButtonOffScreen = getActivity().getButton(offScreenIndex);
+
+        for (int i = 0; i < offScreenIndex; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        getInstrumentation().waitForIdleSync();
+        assertTrue(firstButtonOffScreen.hasFocus());
+
+        assertTrue("the button we've moved to off screen must not be the last "
+                + "button in the scroll view for this test to work (since we "
+                + "are expecting the fading edge to be there).",
+                offScreenIndex < getActivity().getNumButtons());
+
+        // now we are at the first button off screen
+        int buttonLoc[] = {0, 0};
+        firstButtonOffScreen.getLocationOnScreen(buttonLoc);
+        int buttonBottom = buttonLoc[1] + firstButtonOffScreen.getHeight();
+
+        int verticalFadingEdgeLength = mScrollView
+                .getVerticalFadingEdgeLength();
+        assertEquals("bottom of button should be verticalFadingEdgeLength "
+                + "above the bottom of the screen",
+                buttonBottom, mScreenBottom - verticalFadingEdgeLength);
+    }
+
+    // there should be no offset for vertical fading edge
+    // if the item is the last one on screen
+    @LargeTest
+    public void testArrowScrollDownToBottomElementOnScreen() {
+
+        int numGroups = getActivity().getNumButtons();
+        Button lastButton = getActivity().getButton(numGroups - 1);
+
+        assertEquals("button needs to be at the very bottom of the layout for "
+                + "this test to work",
+                mLinearLayout.getHeight(), lastButton.getBottom());
+
+        // move down to last button
+        for (int i = 0; i < numGroups; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        getInstrumentation().waitForIdleSync();
+        assertTrue("last button should have focus", lastButton.hasFocus());
+
+        int buttonLoc[] = {0, 0};
+        lastButton.getLocationOnScreen(buttonLoc);
+        int buttonBottom = buttonLoc[1] + lastButton.getHeight();
+        assertEquals("button should be at very bottom of screen",
+                mScreenBottom, buttonBottom);
+    }
+
+    @LargeTest
+    public void testArrowScrollUpOffScreenVerticalFadingEdge() {
+        // get to bottom button
+        int numGroups = goToBottomButton();
+
+        // go up to first off screen button
+        int offScreenIndex = findFirstButtonOffScreenBottom2Top();
+        Button offScreenButton = getActivity().getButton(offScreenIndex);
+        int clicksToOffScreenIndex = numGroups - offScreenIndex - 1;
+        for (int i = 0; i < clicksToOffScreenIndex; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        }
+        getInstrumentation().waitForIdleSync();
+        assertTrue("we want to be at offScreenButton", offScreenButton.hasFocus());
+
+        // top should take into account fading edge
+        int buttonLoc[] = {0, 0};
+        offScreenButton.getLocationOnScreen(buttonLoc);
+        assertEquals("top should take into account fading edge",
+            mScreenTop + mScrollView.getVerticalFadingEdgeLength(), buttonLoc[1]);
+    }
+
+
+    @LargeTest
+    public void testArrowScrollUpToTopElementOnScreen() {
+        // get to bottom button
+        int numButtons = goToBottomButton();
+
+        // go back to the top
+        for (int i = 0; i < numButtons; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        }
+        getInstrumentation().waitForIdleSync();
+
+        Button topButton = getActivity().getButton(0);
+        assertTrue("should be back at top button", topButton.hasFocus());
+
+
+        int buttonLoc[] = {0, 0};
+        topButton.getLocationOnScreen(buttonLoc);
+        assertEquals("top of top button should be at top of screen; no need to take"
+                + " into account vertical fading edge.",
+                mScreenTop, buttonLoc[1]);
+    }
+
+    private int goToBottomButton() {
+        int numButtons = getActivity().getNumButtons();
+        Button lastButton = getActivity().getButton(numButtons - 1);
+
+        for (int i = 0; i < numButtons; i++) {
+          sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        getInstrumentation().waitForIdleSync();
+        assertTrue("we want to be at the last button", lastButton.hasFocus());
+        return numButtons;
+    }
+
+    // search from top to bottom for the first button off screen
+    private int findFirstButtonOffScreenTop2Bottom() {
+        int origin[] = {0, 0};
+        mScrollView.getLocationOnScreen(origin);
+        int screenHeight = mScrollView.getHeight();
+
+        for (int i = 0; i < getActivity().getNumButtons(); i++) {
+
+            int buttonLoc[] = {0, 0};
+            Button button = getActivity().getButton(i);
+            button.getLocationOnScreen(buttonLoc);
+
+            if (buttonLoc[1] - origin[1] > screenHeight) {
+                return i;
+            }
+        }
+        fail("couldn't find first button off screen");
+        return -1; // this won't execute, but the compiler needs it
+    }
+
+    private int findFirstButtonOffScreenBottom2Top() {
+        int origin[] = {0, 0};
+        mScrollView.getLocationOnScreen(origin);
+
+        for (int i = getActivity().getNumButtons() - 1; i >= 0; i--) {
+
+            int buttonLoc[] = {0, 0};
+            Button button = getActivity().getButton(i);
+            button.getLocationOnScreen(buttonLoc);
+
+            if (buttonLoc[1] < 0) {
+                return i;
+            }
+        }
+        fail("couldn't find first button off screen");
+        return -1; // this won't execute, but the compiler needs it
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
new file mode 100644
index 0000000..6b78560
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.scroll.arrowscroll;
+
+import com.android.frameworktest.scroll.ButtonsWithTallTextViewInBetween;
+
+import android.graphics.Rect;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+public class ButtonsWithTallTextViewInBetweenTest
+        extends ActivityInstrumentationTestCase<ButtonsWithTallTextViewInBetween> {
+
+    private ScrollView mScrollView;
+    private Button mTopButton;
+    private TextView mMiddleFiller;
+    private TextView mBottomButton;
+
+    public ButtonsWithTallTextViewInBetweenTest() {
+        super("com.android.frameworktest", ButtonsWithTallTextViewInBetween.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mScrollView = getActivity().getScrollView();
+        mTopButton = getActivity().getTopButton();
+        mMiddleFiller = getActivity().getMiddleFiller();
+        mBottomButton = getActivity().getBottomButton();
+    }
+
+    private Rect mTempRect = new Rect();
+
+    private int getTopWithinScrollView(View descendant) {
+        descendant.getDrawingRect(mTempRect);
+        mScrollView.offsetDescendantRectToMyCoords(descendant, mTempRect);
+        return mTempRect.top;
+    }
+
+    private int getBottomWithinScrollView(View descendant) {
+        descendant.getDrawingRect(mTempRect);
+        mScrollView.offsetDescendantRectToMyCoords(descendant, mTempRect);
+        return mTempRect.bottom;
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("top button should be shorter than max scroll amount",
+                mTopButton.getHeight() <
+                mScrollView.getMaxScrollAmount());
+        assertTrue("bottom button should be further than max scroll amount off screen",
+                getTopWithinScrollView(mBottomButton)- mScrollView.getBottom() > mScrollView.getMaxScrollAmount());
+    }
+
+    @MediumTest
+    public void testPanTopButtonOffScreenLosesFocus() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertEquals("scroll view should be scrolled by the max amount for one "
+                + "arrow navigation",
+                mScrollView.getMaxScrollAmount(),
+                mScrollView.getScrollY());
+
+        assertTrue("top button should be off screen",
+                getBottomWithinScrollView(mTopButton) < mScrollView.getScrollY());
+
+        assertFalse("top button should have lost focus",
+                mTopButton.isFocused());
+
+        assertTrue("scroll view should be focused", mScrollView.isFocused());
+    }
+
+    @MediumTest
+    public void testScrollDownToBottomButton() throws Exception {
+        final int screenBottom = mScrollView.getScrollY() + mScrollView.getHeight();
+        final int numDownsToButtonButton =
+                ((getBottomWithinScrollView(mBottomButton) - screenBottom)) / mScrollView.getMaxScrollAmount() + 1;
+
+        for (int i = 0; i < numDownsToButtonButton; i++) {
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        assertTrue("bottombutton.isFocused", mBottomButton.isFocused());
+
+        assertEquals("should be fully scrolled to bottom",
+                getActivity().getLinearLayout().getHeight() - mScrollView.getHeight(),
+                mScrollView.getScrollY());
+    }
+
+    @MediumTest
+    public void testPanBottomButtonOffScreenLosesFocus() throws Exception {
+        mBottomButton.post(new Runnable() {
+            public void run() {
+                mBottomButton.requestFocus();
+            }
+        });
+
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("bottombutton.isFocused", mBottomButton.isFocused());
+        final int maxScroll = getActivity().getLinearLayout().getHeight()
+                - mScrollView.getHeight();
+        assertEquals("should be fully scrolled to bottom",
+                maxScroll,
+                mScrollView.getScrollY());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+        assertEquals("scroll view should have scrolled by the max amount for one "
+                + "arrow navigation",
+                maxScroll - mScrollView.getMaxScrollAmount(),
+                mScrollView.getScrollY());
+
+        assertTrue("bottom button should be off screen",
+                getTopWithinScrollView(mBottomButton) > mScrollView.getScrollY() + mScrollView.getHeight());
+
+        assertFalse("bottom button should have lost focus",
+                mBottomButton.isFocused());
+
+        assertTrue("scroll view should be focused", mScrollView.isFocused());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ShortButtonsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ShortButtonsTest.java
new file mode 100644
index 0000000..689eb19
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ShortButtonsTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.scroll.arrowscroll;
+
+import com.android.frameworktest.scroll.ShortButtons;
+
+import android.graphics.Rect;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.ScrollView;
+
+public class ShortButtonsTest extends ActivityInstrumentationTestCase<ShortButtons> {
+
+    private ScrollView mScrollView;
+
+    public ShortButtonsTest() {
+        super("com.android.frameworktest", ShortButtons.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mScrollView = getActivity().getScrollView();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("buttons should be shorter than screen",
+                getActivity().getButtonAt(0).getHeight()
+                        < mScrollView.getHeight());
+
+        assertTrue("should be enough buttons to have some scrolled off screen",
+                getActivity().getLinearLayout().getHeight()
+                        > getActivity().getScrollView().getHeight());
+    }
+
+    @LargeTest
+    public void testScrollDownToBottomThroughButtons() throws Exception {
+        final int numButtons = getActivity().getNumButtons();
+
+        for (int i = 0; i < numButtons; i++) {
+            String prefix = "after " + i + " downs expected button " + i;
+            final Button button = getActivity().getButtonAt(i);
+            assertTrue(prefix + "  to have focus", button.isFocused());
+            assertTrue(prefix + " to be on screen", isButtonOnScreen(button));
+            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        assertEquals("should be fully scrolled to bottom",
+                getActivity().getLinearLayout().getHeight() - mScrollView.getHeight(),
+                mScrollView.getScrollY());        
+    }
+
+    @LargeTest
+    public void testScrollFromBottomToTopThroughButtons() throws Exception {
+        final int numButtons = getActivity().getNumButtons();
+
+        final Button lastButton = getActivity().getButtonAt(numButtons - 1);
+
+        lastButton.post(new Runnable() {
+            public void run() {
+                lastButton.requestFocus();
+            }
+        });
+
+        getInstrumentation().waitForIdleSync();
+
+        assertTrue("lastButton.isFocused()", lastButton.isFocused());
+
+        for (int i = numButtons - 1; i >= 0; i--) {
+            String prefix = "after " + i + " ups expected button " + i;
+            final Button button = getActivity().getButtonAt(i);
+            assertTrue(prefix + "  to have focus", button.isFocused());
+            assertTrue(prefix + " to be on screen", isButtonOnScreen(button));
+            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        }
+
+        assertEquals("should be fully scrolled to top",
+                0,
+                mScrollView.getScrollY());        
+    }
+
+    private Rect mTempRect = new Rect();
+    protected boolean isButtonOnScreen(Button b) {
+        b.getDrawingRect(mTempRect);
+        mScrollView.offsetDescendantRectToMyCoords(b, mTempRect);
+        return mTempRect.bottom >= mScrollView.getScrollY()
+                && mTempRect.top <= (mScrollView.getScrollY() + mScrollView.getHeight());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/TallTextAboveButtonTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/TallTextAboveButtonTest.java
new file mode 100644
index 0000000..573045d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/TallTextAboveButtonTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.scroll.arrowscroll;
+
+import com.android.frameworktest.scroll.TallTextAboveButton;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+public class TallTextAboveButtonTest extends ActivityInstrumentationTestCase<TallTextAboveButton> {
+    private ScrollView mScrollView;
+    private TextView mTopText;
+    private TextView mBottomButton;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mScrollView = getActivity().getScrollView();
+        mTopText = getActivity().getContentChildAt(0);
+        mBottomButton = getActivity().getContentChildAt(1);
+    }
+
+    public TallTextAboveButtonTest() {
+        super("com.android.frameworktest", TallTextAboveButton.class);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("top text should be larger than screen",
+                mTopText.getHeight() > mScrollView.getHeight());
+        assertTrue("scroll view should have focus (because nothing else focusable "
+                + "is on screen), but " + getActivity().getScrollView().findFocus() + " does instead",
+                getActivity().getScrollView().isFocused());
+    }
+
+    @MediumTest
+    public void testGainFocusAsScrolledOntoScreen() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertTrue("button should have scrolled onto screen",
+                mBottomButton.getBottom() >= mScrollView.getBottom());
+        assertTrue("button should have gained focus as it was scrolled completely "
+                + "into view", mBottomButton.isFocused());
+
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue("scroll view should have focus, but " + getActivity().getScrollView().findFocus() + " does instead",
+                getActivity().getScrollView().isFocused());
+    }
+
+    @MediumTest
+    public void testScrollingButtonOffScreenLosesFocus() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue("button should have focus", mBottomButton.isFocused());
+        sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+        assertTrue("scroll view should have focus, but " + getActivity().getScrollView().findFocus() + " does instead",
+                getActivity().getScrollView().isFocused());
+    }
+    
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/settings/RingtonePickerActivityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/settings/RingtonePickerActivityTest.java
new file mode 100644
index 0000000..42888ff
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/settings/RingtonePickerActivityTest.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.settings;
+
+import com.android.frameworktest.settings.RingtonePickerActivityLauncher;
+
+import android.app.Instrumentation;
+import android.database.Cursor;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.view.KeyEvent;
+
+/**
+ * Tests the RingtonePickerActivity.
+ * <p>
+ * There is a launcher for launching the RingtonePickerActivity (RPA) since the RPA needs
+ * to be a subactivity.  We don't have a reference to the actual RPA.
+ * <p>
+ * This relies heavily on keypresses getting to the right widget.  It depends on:
+ * <li> Less than NUM_RINGTONES_AND_SOME ringtones on the system
+ * <li> Pressing arrow-down a ton will eventually end up on the 'Cancel' button
+ * <li> From the 'Cancel' button, pressing arrow-left will end up on 'OK' button
+ */
+@Suppress
+public class RingtonePickerActivityTest extends ActivityInstrumentationTestCase<RingtonePickerActivityLauncher> {
+
+    private static final int NUM_RINGTONES_AND_SOME = 20;
+    private RingtonePickerActivityLauncher mActivity;
+    private Instrumentation mInstrumentation;
+    
+    public RingtonePickerActivityTest() {
+        super("com.android.frameworktest", RingtonePickerActivityLauncher.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        mActivity = getActivity();
+        mInstrumentation = getInstrumentation();
+        assertNotNull(mActivity);
+        assertFalse(mActivity.resultReceived);
+        assertNotNull(mInstrumentation);
+    }
+    
+    public void testDefault() {
+        mActivity.launchRingtonePickerActivity(true, null, RingtoneManager.TYPE_ALL);
+        mInstrumentation.waitForIdleSync();
+        
+        // Go to top
+        goTo(true);
+        // Select default ringtone 
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        // Go to bottom/cancel button
+        goTo(false);
+        // Select OK button
+        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+        
+        mInstrumentation.waitForIdleSync();
+        
+        assertTrue(mActivity.resultReceived);
+        assertNotNull(mActivity.result);
+        assertTrue(RingtoneManager.isDefault(mActivity.pickedUri));
+    }
+    
+    public void testFirst() {
+        mActivity.launchRingtonePickerActivity(true, null, RingtoneManager.TYPE_ALL);
+        mInstrumentation.waitForIdleSync();
+        
+        // Go to top
+        goTo(true);
+        // Select first (non-default) ringtone 
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
+        // Go to bottom/cancel button
+        goTo(false);
+        // Select OK button
+        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+        
+        mInstrumentation.waitForIdleSync();
+        
+        assertTrue(mActivity.resultReceived);
+        assertNotNull(mActivity.result);
+        assertNotNull(mActivity.pickedUri);
+        assertFalse(RingtoneManager.isDefault(mActivity.pickedUri));
+    }
+
+    public void testExisting() {
+        // We need to get an existing ringtone first, so launch it, pick first,
+        // and keep that URI
+        testFirst();
+        Uri firstUri = mActivity.pickedUri;
+        
+        mActivity.launchRingtonePickerActivity(true, firstUri, RingtoneManager.TYPE_ALL);
+        mInstrumentation.waitForIdleSync();
+
+        //// Hit cancel:
+        
+        // Go to bottom
+        goTo(false);
+        // Select Cancel button
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        
+        mInstrumentation.waitForIdleSync();
+        
+        assertTrue(mActivity.resultReceived);
+        assertEquals(mActivity.pickedUri, firstUri);
+    }
+    
+    public void testExistingButDifferent() {
+        // We need to get an existing ringtone first, so launch it, pick first,
+        // and keep that URI
+        testFirst();
+        Uri firstUri = mActivity.pickedUri;
+        
+        mActivity.launchRingtonePickerActivity(true, firstUri, RingtoneManager.TYPE_ALL);
+        mInstrumentation.waitForIdleSync();
+
+        //// Pick second:
+        
+        // Go to top
+        goTo(true);
+        // Select second (non-default) ringtone 
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_DOWN,
+                KeyEvent.KEYCODE_DPAD_CENTER);
+        // Go to bottom/cancel button
+        goTo(false);
+        // Select OK button
+        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+        
+        mInstrumentation.waitForIdleSync();
+        
+        assertTrue(mActivity.resultReceived);
+        assertNotNull(mActivity.result);
+        assertTrue(!firstUri.equals(mActivity.pickedUri));
+    }
+    
+    public void testCancel() {
+        mActivity.launchRingtonePickerActivity(true, null, RingtoneManager.TYPE_ALL);
+        mInstrumentation.waitForIdleSync();
+        
+        // Go to bottom
+        goTo(false);
+        // Select Cancel button
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        
+        mInstrumentation.waitForIdleSync();
+        
+        assertTrue(mActivity.resultReceived);
+        assertNull(mActivity.result);
+    }
+
+    public void testNoDefault() {
+        mActivity.launchRingtonePickerActivity(false, null, RingtoneManager.TYPE_ALL);
+        mInstrumentation.waitForIdleSync();
+        
+        // Go to top
+        goTo(true);
+        // Select first (non-default) ringtone 
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        // Go to bottom/cancel button
+        goTo(false);
+        // Select OK button
+        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+        
+        mInstrumentation.waitForIdleSync();
+        
+        assertTrue(mActivity.resultReceived);
+        assertNotNull(mActivity.result);
+        assertNotNull(mActivity.pickedUri);
+        assertFalse(RingtoneManager.isDefault(mActivity.pickedUri));
+    }
+    
+    public void testNotifications() {
+        mActivity.launchRingtonePickerActivity(false, null, RingtoneManager.TYPE_NOTIFICATION);
+        mInstrumentation.waitForIdleSync();
+        
+        // Move to top of list
+        goTo(true);
+        // Select first ringtone in list
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        // Move all the way down (will focus 'Cancel')
+        goTo(false);
+        // Move left and click (will click 'Ok')
+        sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+
+        // Wait until main thread is idle
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mActivity.resultReceived);
+        assertNotNull(mActivity.result);
+        assertNotNull(mActivity.pickedUri);
+        
+        // Get the path of the picked ringtone
+        Uri uri = mActivity.pickedUri;
+        Cursor c = mActivity.getContentResolver().query(uri, new String[] { "_data" },
+                null, null, null);
+        assertTrue("Query for selected ringtone URI does not have a result", c.moveToFirst());
+        String path = c.getString(0);
+        // Quick check to see if the ringtone is a notification
+        assertTrue("The path of the selected ringtone did not contain \"notification\"",
+                path.contains("notifications"));
+    }
+    
+    private void goTo(boolean top) {
+        // Get to the buttons at the bottom (top == false), or the top (top == true)
+        for (int i = 0; i < NUM_RINGTONES_AND_SOME; i++) {
+            sendKeys(top ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/text/HtmlTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/HtmlTest.java
new file mode 100644
index 0000000..9b309c4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/HtmlTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.text;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.Html;
+import android.text.Spanned;
+import android.text.style.StyleSpan;
+import android.graphics.Typeface;
+
+public class HtmlTest extends InstrumentationTestCase {
+
+    @MediumTest
+    public void testSingleTagOnWhileString() {
+        Spanned spanned = Html.fromHtml("<b>hello</b>");
+        Object[] spans = spanned.getSpans(-1, 100, Object.class);
+        assertEquals(1, spans.length);
+        Object span = spans[0];
+        assertEquals(0, spanned.getSpanStart(span));
+        assertEquals(5, spanned.getSpanEnd(span));
+    }
+
+    @MediumTest
+    public void testEmptyFontTag() {
+        Spanned spanned = Html.fromHtml("Hello <font color=\"#ff00ff00\"></font>");
+        Object[] spans = spanned.getSpans(0, 100, Object.class);
+        // TODO: figure out what the spans should be after the crashes are fixed and assert them.
+    }
+
+    /** Tests that the parser can handle mal-formed HTML. */
+    @MediumTest
+    public void testBadHtml() {
+        Spanned spanned = Html.fromHtml("Hello <b>b<i>bi</b>i</i>");
+        Object[] spans = spanned.getSpans(0, 100, Object.class);
+        assertEquals(Typeface.ITALIC, ((StyleSpan) spans[0]).getStyle());
+        assertEquals(7, spanned.getSpanStart(spans[0]));
+        assertEquals(9, spanned.getSpanEnd(spans[0]));
+        assertEquals(Typeface.BOLD, ((StyleSpan) spans[1]).getStyle());
+        assertEquals(6, spanned.getSpanStart(spans[1]));
+        assertEquals(9, spanned.getSpanEnd(spans[1]));
+        assertEquals(Typeface.ITALIC, ((StyleSpan) spans[2]).getStyle());
+        assertEquals(9, spanned.getSpanStart(spans[2]));
+        assertEquals(10, spanned.getSpanEnd(spans[2]));
+    }
+
+    @MediumTest
+    public void testSymbols() {
+        String spanned = Html.fromHtml("&copy; &gt; &lt").toString();
+        assertEquals("\u00a9 > <", spanned);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringBuilderTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringBuilderTest.java
new file mode 100644
index 0000000..a807977
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringBuilderTest.java
@@ -0,0 +1,11 @@
+package com.android.frameworktest.text;
+
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+
+public class SpannableStringBuilderTest extends SpannableTest {
+
+    protected Spannable newSpannableWithText(String text) {
+        return new SpannableStringBuilder(text);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringTest.java
new file mode 100644
index 0000000..311df23
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringTest.java
@@ -0,0 +1,11 @@
+package com.android.frameworktest.text;
+
+import android.text.Spannable;
+import android.text.SpannableString;
+
+public class SpannableStringTest extends SpannableTest {
+
+    protected Spannable newSpannableWithText(String text) {
+        return new SpannableString(text);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableTest.java
new file mode 100644
index 0000000..a5f6836
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableTest.java
@@ -0,0 +1,34 @@
+package com.android.frameworktest.text;
+
+import android.test.InstrumentationTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.Spannable;
+
+public abstract class SpannableTest extends InstrumentationTestCase {
+
+    protected abstract Spannable newSpannableWithText(String text);
+
+    @MediumTest
+    public void testGetSpans() {
+        Spannable spannable = newSpannableWithText("abcdef");
+        Object emptySpan = new Object();
+        spannable.setSpan(emptySpan, 1, 1, 0);
+        Object unemptySpan = new Object();
+        spannable.setSpan(unemptySpan, 1, 2, 0);
+
+        Object[] spans;
+
+        // Empty spans are included when they merely abut the query region
+        // but other spans are not, unless the query region is empty, in
+        // in which case any abutting spans are returned.
+        spans = spannable.getSpans(0, 1, Object.class);
+        MoreAsserts.assertEquals(new Object[]{emptySpan}, spans);
+        spans = spannable.getSpans(0, 2, Object.class);
+        MoreAsserts.assertEquals(new Object[]{emptySpan, unemptySpan}, spans);
+        spans = spannable.getSpans(1, 2, Object.class);
+        MoreAsserts.assertEquals(new Object[]{emptySpan, unemptySpan}, spans);
+        spans = spannable.getSpans(2, 2, Object.class);
+        MoreAsserts.assertEquals(new Object[]{unemptySpan}, spans);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/ChangeTouchModeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/ChangeTouchModeTest.java
new file mode 100644
index 0000000..d274d0d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/ChangeTouchModeTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLOfButtons1;
+import com.android.frameworktest.layout.linear.LLOfButtons2;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+/**
+ * Tests that the touch mode changes from various events, and that the state
+ * persists across activities.
+ */
+public class ChangeTouchModeTest extends ActivityInstrumentationTestCase<LLOfButtons1> {
+
+    public ChangeTouchModeTest() {
+        super("com.android.frameworktest", LLOfButtons1.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @MediumTest
+    public void testPreconditions() throws Exception {
+        assertFalse("touch mode", getActivity().isInTouchMode());
+    }
+
+    @MediumTest
+    public void testTouchingScreenEntersTouchMode() throws Exception {
+        assertInTouchModeAfterTap(this, getActivity().getFirstButton());
+        assertTrue("touch mode", getActivity().isInTouchMode());
+    }
+
+    // TODO: reenable when more reliable
+    public void DISABLE_testDpadDirectionLeavesTouchMode() throws Exception {
+        assertInTouchModeAfterClick(this, getActivity().getFirstButton());
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+        assertNotInTouchModeAfterKey(this, KeyEvent.KEYCODE_DPAD_RIGHT, getActivity().getFirstButton());
+        assertFalse("touch mode", getActivity().isInTouchMode());
+    }
+
+    public void TODO_touchTrackBallMovementLeavesTouchMode() throws Exception {
+
+    }
+
+    @MediumTest
+    public void testTouchModeFalseAcrossActivites() throws Exception {
+
+        getInstrumentation().waitForIdleSync();
+
+        LLOfButtons2 otherActivity = null;
+        try {
+            otherActivity =
+                    launchActivity("com.android.frameworktest", LLOfButtons2.class, null);
+            assertNotNull(otherActivity);
+            assertFalse(otherActivity.isInTouchMode());
+        } finally {
+            if (otherActivity != null) {
+                otherActivity.finish();
+            }
+        }
+    }
+
+    @LargeTest
+    public void testTouchModeTrueAcrossActivites() throws Exception {
+        assertInTouchModeAfterClick(this, getActivity().getFirstButton());
+        LLOfButtons2 otherActivity = null;
+        try {
+            otherActivity =
+                    launchActivity("com.android.frameworktest", LLOfButtons2.class, null);
+            assertNotNull(otherActivity);
+            assertTrue(otherActivity.isInTouchMode());
+        } finally {
+            if (otherActivity != null) {
+                otherActivity.finish();
+            }
+        }
+    }
+
+    @LargeTest
+    public void testTouchModeChangedInOtherActivity() throws Exception {
+
+        assertFalse("touch mode", getActivity().isInTouchMode());
+
+        LLOfButtons2 otherActivity = null;
+        try {
+            otherActivity =
+                    launchActivity("com.android.frameworktest", LLOfButtons2.class, null);
+            assertNotNull(otherActivity);
+            assertFalse(otherActivity.isInTouchMode());
+            assertInTouchModeAfterClick(this, otherActivity.getFirstButton());
+            assertTrue(otherActivity.isInTouchMode());
+        } finally {
+            if (otherActivity != null) {
+                otherActivity.finish();
+            }
+        }
+
+        // need to wait for async update back to window to occur
+        Thread.sleep(200);
+        
+        assertTrue("touch mode", getActivity().isInTouchMode());
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/FocusableInTouchModeClickTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/FocusableInTouchModeClickTest.java
new file mode 100644
index 0000000..7cd6444
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/FocusableInTouchModeClickTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLOfTwoFocusableInTouchMode;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class FocusableInTouchModeClickTest extends ActivityInstrumentationTestCase2<LLOfTwoFocusableInTouchMode> {
+
+    public FocusableInTouchModeClickTest() {
+        super("com.android.frameworktest", LLOfTwoFocusableInTouchMode.class);
+    }
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        setActivityInitialTouchMode(true);
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("should start in touch mode", getActivity().getButton1().isInTouchMode());
+        assertTrue(getActivity().getButton1().isFocused());
+    }
+
+    @LargeTest
+    public void testClickGivesFocusNoClickFired() {
+        TouchUtils.clickView(this, getActivity().getButton2());
+        assertTrue("click should give focusable in touch mode focus",
+                getActivity().getButton2().isFocused());
+        assertFalse("getting focus should result in no on click",
+                getActivity().isB2Fired());
+
+        TouchUtils.clickView(this, getActivity().getButton2());
+        assertTrue("subsequent click while focused should fire on click",
+                getActivity().isB2Fired());
+    }
+
+    @MediumTest
+    public void testTapGivesFocusNoClickFired() {
+        TouchUtils.touchAndCancelView(this, getActivity().getButton2());
+        assertFalse("button shouldn't have fired click", getActivity().isB2Fired());
+        assertFalse("button shouldn't have focus", getActivity().getButton2().isFocused());
+    }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/StartInTouchWithViewInFocusTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/StartInTouchWithViewInFocusTest.java
new file mode 100644
index 0000000..6403435
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/StartInTouchWithViewInFocusTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLEditTextThenButton;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.EditText;
+
+public class StartInTouchWithViewInFocusTest extends 
+        ActivityInstrumentationTestCase2<LLEditTextThenButton> {
+
+    private EditText mEditText;
+
+    private Button mButton;
+
+    public StartInTouchWithViewInFocusTest() {
+        super("com.android.frameworktest", LLEditTextThenButton.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        this.setActivityInitialTouchMode(true);
+        mEditText = getActivity().getEditText();
+        mButton = getActivity().getButton();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertTrue("should start in touch mode", mEditText.isInTouchMode());
+        assertTrue("edit text is focusable in touch mode, should have focus", mEditText.isFocused());
+    }
+
+    // TODO: reenable when more reliable
+    public void DISABLE_testKeyDownLeavesTouchModeAndGoesToNextView() {
+        assertNotInTouchModeAfterKey(this, KeyEvent.KEYCODE_DPAD_DOWN, mEditText);
+        assertFalse("should have left touch mode", mEditText.isInTouchMode());
+        assertTrue("should have given focus to next view", mButton.isFocused());
+    }
+
+    // TODO: reenable when more reliable
+    public void DISABLE_testNonDirectionalKeyExitsTouchMode() {
+        assertNotInTouchModeAfterKey(this, KeyEvent.KEYCODE_A, mEditText);
+        assertFalse("should have left touch mode", mEditText.isInTouchMode());
+        assertTrue("edit text should still have focus", mEditText.isFocused());        
+    }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusChangeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusChangeTest.java
new file mode 100644
index 0000000..1a0c833
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusChangeTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLOfButtons1;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+/**
+ * Make sure focus isn't kept by buttons when entering touch mode.
+ *
+ * When in touch mode and hitting the d-pad, we should leave touch mode and the
+ * top most focusable gets focus.
+ */
+public class TouchModeFocusChangeTest extends ActivityInstrumentationTestCase<LLOfButtons1> {
+    private LLOfButtons1 mActivity;
+    private Button mFirstButton;
+
+    public TouchModeFocusChangeTest() {
+        super("com.android.frameworktest", LLOfButtons1.class);
+    }
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mFirstButton = mActivity.getFirstButton();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertFalse("we should not be in touch mode", mActivity.isInTouchMode());
+        assertTrue("top button should have focus", mFirstButton.isFocused());
+    }
+
+    @MediumTest
+    public void testTouchButtonNotTakeFocus() {
+        assertInTouchModeAfterTap(this, mFirstButton);
+
+        assertTrue("should be in touch mode", mActivity.isInTouchMode());
+        assertFalse("button.isFocused",
+                mFirstButton.isFocused());
+        assertFalse("button.hasFocus",
+                mFirstButton.hasFocus());
+        assertNull("activity shouldn't have focus", mActivity.getCurrentFocus());
+        assertFalse("linear layout should not have focus",
+                mActivity.getLayout().hasFocus());
+
+        assertTrue("button's onClickListener should have fired",
+                mActivity.buttonClickListenerFired());
+    }
+
+    // TODO: reenable when more reliable
+    public void DISABLE_testLeaveTouchModeWithDpadEvent() {
+        assertInTouchModeAfterClick(this, mFirstButton);
+
+        assertTrue("should be in touch mode", mActivity.isInTouchMode());
+        assertFalse("button should not have focus when touched",
+                mFirstButton.isFocused());
+
+        assertNotInTouchModeAfterKey(this, KeyEvent.KEYCODE_DPAD_RIGHT, mFirstButton);
+        assertFalse("should be out of touch mode", mActivity.isInTouchMode());
+        assertTrue("first button (the top most focusable) should have gained focus",
+                mFirstButton.isFocused());
+    }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusableTest.java
new file mode 100644
index 0000000..86925b5
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusableTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLEditTextThenButton;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.EditText;
+
+/**
+ * Some views, like edit texts, can keep and gain focus even when in touch mode.
+ */
+public class TouchModeFocusableTest extends ActivityInstrumentationTestCase<LLEditTextThenButton> {
+    private EditText mEditText;
+    private Button mButton;
+
+
+    public TouchModeFocusableTest() {
+        super("com.android.frameworktest", LLEditTextThenButton.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mEditText = getActivity().getEditText();
+        mButton = getActivity().getButton();
+    }
+
+    @MediumTest
+    public void testPreconditions() {
+        assertFalse("should not be in touch mode to start off", mButton.isInTouchMode());
+        assertTrue("edit text should have focus", mEditText.isFocused());
+        assertTrue("edit text should be focusable in touch mode", mEditText.isFocusableInTouchMode());
+    }
+
+    @MediumTest
+    public void testClickButtonEditTextKeepsFocus() {
+        assertInTouchModeAfterTap(this, mButton);
+        assertTrue("should be in touch mode", mButton.isInTouchMode());
+        assertTrue("edit text should still have focus", mEditText.isFocused());
+    }
+
+    @LargeTest
+    public void testClickEditTextGivesItFocus() {
+        // go down to button
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue("button should have focus", mButton.isFocused());
+
+        assertInTouchModeAfterClick(this, mEditText);
+        assertTrue("clicking edit text should have entered touch mode", mButton.isInTouchMode());
+        assertTrue("clicking edit text should have given it focus", mEditText.isFocused());
+    }
+
+
+    // entering touch mode takes focus away from the currently focused item if it
+    // isn't focusable in touch mode.
+    @LargeTest
+    public void testEnterTouchModeGivesFocusBackToFocusableInTouchMode() {
+        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertTrue("button should have focus",
+                mButton.isFocused());
+        
+        assertInTouchModeAfterClick(this, mButton);
+        assertTrue("should be in touch mode", mButton.isInTouchMode());
+        assertNull("nothing should have focus", getActivity().getCurrentFocus());
+        assertFalse("layout should not have focus",
+                getActivity().getLayout().hasFocus());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/BigCacheTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/BigCacheTest.java
new file mode 100644
index 0000000..b5e7473
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/BigCacheTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.view.BigCache;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.graphics.Bitmap;
+
+/**
+ * Builds the drawing cache of two Views, one smaller than the maximum cache size,
+ * one larger than the maximum cache size. The latter should always have a null
+ * drawing cache.
+ */
+public class BigCacheTest extends ActivityInstrumentationTestCase<BigCache> {
+    private View mTiny;
+    private View mLarge;
+
+    public BigCacheTest() {
+        super("com.android.frameworktest", BigCache.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final BigCache activity = getActivity();
+        mTiny = activity.findViewById(R.id.a);
+        mLarge = activity.findViewById(R.id.b);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mTiny);
+        assertNotNull(mLarge);
+    }
+
+    @MediumTest
+    public void testDrawingCacheBelowMaximumSize() throws Exception {
+        final int max = ViewConfiguration.getMaximumDrawingCacheSize();
+        assertTrue(mTiny.getWidth() * mTiny.getHeight() * 2 < max);
+        assertNotNull(createCacheForView(mTiny));
+    }
+
+    @MediumTest
+    public void testDrawingCacheAboveMaximumSize() throws Exception {
+        final int max = ViewConfiguration.getMaximumDrawingCacheSize();
+        assertTrue(mLarge.getWidth() * mLarge.getHeight() * 2 > max);
+        assertNull(createCacheForView(mLarge));
+    }
+
+    private Bitmap createCacheForView(final View view) {
+        final Bitmap[] cache = new Bitmap[1];
+        getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                view.setDrawingCacheEnabled(true);
+                view.invalidate();
+                view.buildDrawingCache();
+                cache[0] = view.getDrawingCache();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        return cache[0];
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledLongpressTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledLongpressTest.java
new file mode 100644
index 0000000..ef3ecee
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledLongpressTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.view.Longpress;
+import com.android.frameworktest.R;
+import com.android.frameworktest.util.KeyUtils;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.view.View.OnLongClickListener;
+
+/**
+ * Exercises {@link android.view.View}'s longpress plumbing by testing the
+ * disabled case.
+ */
+public class DisabledLongpressTest extends ActivityInstrumentationTestCase<Longpress> {
+    private View mSimpleView;
+    private boolean mLongClicked;
+    
+    public DisabledLongpressTest() {
+        super("com.android.frameworktest", Longpress.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final Longpress a = getActivity();
+        mSimpleView = a.findViewById(R.id.simple_view);
+        mSimpleView.setOnLongClickListener(new OnLongClickListener() {
+            public boolean onLongClick(View v) {
+                mLongClicked = true;
+                return true;
+            }
+        });
+        // The View#setOnLongClickListener will ensure the View is long
+        // clickable, we reverse that here
+        mSimpleView.setLongClickable(false);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        mLongClicked = false;
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mSimpleView);
+        assertTrue(mSimpleView.hasFocus());
+        assertFalse(mLongClicked);
+    }
+
+    @LargeTest
+    public void testKeypadLongClick() throws Exception {
+        mSimpleView.requestFocus();
+        getInstrumentation().waitForIdleSync();
+        KeyUtils.longClick(this);
+        
+        getInstrumentation().waitForIdleSync();
+        assertFalse(mLongClicked);
+    }
+
+    @LargeTest
+    public void testTouchLongClick() throws Exception {
+        TouchUtils.longClickView(this, mSimpleView);
+        getInstrumentation().waitForIdleSync();
+        assertFalse(mLongClicked);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledTest.java
new file mode 100644
index 0000000..d9ed033
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.widget.Button;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * Exercises {@link android.view.View}'s disabled property.
+ */
+public class DisabledTest extends ActivityInstrumentationTestCase<Disabled> {
+    private Button mDisabled;
+    private View mDisabledParent;
+    private boolean mClicked;
+    private boolean mParentClicked;
+
+    public DisabledTest() {
+        super("com.android.frameworktest", Disabled.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final Disabled a = getActivity();
+        mDisabled = (Button) a.findViewById(R.id.disabledButton);
+        mDisabled.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mClicked = true;
+            }
+        });
+
+        mDisabledParent = a.findViewById(R.id.clickableParent);
+        mDisabledParent.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                mParentClicked = true;
+            }
+        });
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        mClicked = false;
+        mParentClicked = false;
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mDisabled);
+        assertNotNull(mDisabledParent);
+        assertFalse(mDisabled.isEnabled());
+        assertTrue(mDisabledParent.isEnabled());
+        assertTrue(mDisabled.hasFocus());
+    }
+
+    @MediumTest
+    public void testKeypadClick() throws Exception {
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        getInstrumentation().waitForIdleSync();
+        assertFalse(mClicked);
+        assertFalse(mParentClicked);
+    }
+
+    @LargeTest
+    public void testTouchClick() throws Exception {
+        TouchUtils.clickView(this, mDisabled);
+        getInstrumentation().waitForIdleSync();
+        assertFalse(mClicked);
+        assertFalse(mParentClicked);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/GlobalFocusChangeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/GlobalFocusChangeTest.java
new file mode 100644
index 0000000..8a8d728
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/GlobalFocusChangeTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.view.KeyEvent;
+import com.android.frameworktest.R;
+
+public class GlobalFocusChangeTest extends ActivityInstrumentationTestCase<GlobalFocusChange> {
+    private GlobalFocusChange mActivity;
+    private View mLeft;
+    private View mRight;
+
+    public GlobalFocusChangeTest() {
+        super("com.android.frameworktest", GlobalFocusChange.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mActivity = getActivity();
+        mLeft = mActivity.findViewById(R.id.left);
+        mRight = mActivity.findViewById(R.id.right);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mActivity.reset();
+        super.tearDown();
+    }
+
+    @FlakyTest(tolerance = 4)
+    @LargeTest
+    public void testFocusChange() throws Exception {
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+
+        assertFalse(mLeft.isFocused());
+        assertTrue(mRight.isFocused());
+
+        assertSame(mLeft, mActivity.mOldFocus);
+        assertSame(mRight, mActivity.mNewFocus);        
+    }
+
+    @FlakyTest(tolerance = 4)
+    @MediumTest
+    public void testEnterTouchMode() throws Exception {
+        assertTrue(mLeft.isFocused());
+
+        TouchUtils.tapView(this, mLeft);
+
+        assertSame(mLeft, mActivity.mOldFocus);
+        assertSame(null, mActivity.mNewFocus);        
+    }
+
+    @FlakyTest(tolerance = 4)
+    @MediumTest
+    public void testLeaveTouchMode() throws Exception {
+        assertTrue(mLeft.isFocused());
+
+        TouchUtils.tapView(this, mLeft);
+        sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+
+        assertTrue(mLeft.isFocused());
+
+        assertSame(null, mActivity.mOldFocus);
+        assertSame(mLeft, mActivity.mNewFocus);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/IncludeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/IncludeTest.java
new file mode 100644
index 0000000..dd1382d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/IncludeTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.view.Include;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class IncludeTest extends ActivityInstrumentationTestCase<Include> {
+    public IncludeTest() {
+        super("com.android.frameworktest", Include.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @MediumTest
+    public void testIncluded() throws Exception {
+        final Include activity = getActivity();
+
+        final View button1 = activity.findViewById(R.id.included_button);
+        assertNotNull("The layout include_button was not included", button1);
+
+        final View button2 = activity.findViewById(R.id.included_button_overriden);
+        assertNotNull("The layout include_button was not included with overriden id", button2);
+    }
+
+    @MediumTest
+    public void testIncludedWithLayoutParams() throws Exception {
+        final Include activity = getActivity();
+
+        final View button1 = activity.findViewById(R.id.included_button);
+        final View button2 = activity.findViewById(R.id.included_button_overriden);
+
+        assertTrue("Both buttons should have different width",
+                button1.getLayoutParams().width != button2.getLayoutParams().width);
+        assertTrue("Both buttons should have different height",
+                button1.getLayoutParams().height != button2.getLayoutParams().height);
+    }
+
+    @MediumTest
+    public void testIncludedWithVisibility() throws Exception {
+        final Include activity = getActivity();
+        final View button1 = activity.findViewById(R.id.included_button_visibility);
+
+        assertEquals("Included button should be invisible", View.INVISIBLE, button1.getVisibility());
+    }
+
+    @MediumTest
+    public void testIncludedWithSize() throws Exception {
+        final Include activity = getActivity();
+        final View button1 = activity.findViewById(R.id.included_button_with_size);
+
+        final ViewGroup.LayoutParams lp = button1.getLayoutParams();
+        assertEquals("Included button should be 23dip x 23dip", 23, lp.width);
+        assertEquals("Included button should be 23dip x 23dip", 23, lp.height);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/LongpressTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/LongpressTest.java
new file mode 100644
index 0000000..37106f6
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/LongpressTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.view.Longpress;
+import com.android.frameworktest.R;
+import com.android.frameworktest.util.KeyUtils;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.view.View.OnLongClickListener;
+
+/**
+ * Exercises {@link android.view.View}'s longpress plumbing.
+ */
+public class LongpressTest extends ActivityInstrumentationTestCase<Longpress> {
+    private View mSimpleView;
+    private boolean mLongClicked;
+    
+    public LongpressTest() {
+        super("com.android.frameworktest", Longpress.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final Longpress a = getActivity();
+        mSimpleView = a.findViewById(R.id.simple_view);
+        mSimpleView.setOnLongClickListener(new OnLongClickListener() {
+            public boolean onLongClick(View v) {
+                mLongClicked = true;
+                return true;
+            }
+        });
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+
+        mLongClicked = false;
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mSimpleView);
+        assertTrue(mSimpleView.hasFocus());
+        assertFalse(mLongClicked);
+    }
+
+    @LargeTest
+    public void testKeypadLongClick() throws Exception {
+        mSimpleView.requestFocus();
+        getInstrumentation().waitForIdleSync();
+        KeyUtils.longClick(this);
+        
+        getInstrumentation().waitForIdleSync();
+        assertTrue(mLongClicked);
+    }
+
+    @LargeTest
+    public void testTouchLongClick() throws Exception {
+        TouchUtils.longClickView(this, mSimpleView);
+        getInstrumentation().waitForIdleSync();
+        assertTrue(mLongClicked);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/MergeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/MergeTest.java
new file mode 100644
index 0000000..612ebd4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/MergeTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.view.Merge;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.ViewGroup;
+
+public class MergeTest extends ActivityInstrumentationTestCase<Merge> {
+    public MergeTest() {
+        super("com.android.frameworktest", Merge.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @MediumTest
+    public void testMerged() throws Exception {
+        final Merge activity = getActivity();
+        final ViewGroup layout = activity.getLayout();
+
+        assertEquals("The layout wasn't merged", 7, layout.getChildCount());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java
new file mode 100644
index 0000000..3dcb252
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008 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.frameworktest.view;
+
+import android.os.Parcel;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.InflateException;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RemoteViews;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.view.RemoteViewsActivity;
+
+public class RemoteViewsActivityTest extends ActivityInstrumentationTestCase<RemoteViewsActivity> {
+    public RemoteViewsActivityTest() {
+        super("com.android.frameworktest", RemoteViewsActivity.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @MediumTest
+    public void testGood() throws Exception {
+        final RemoteViewsActivity activity = getActivity();
+
+        RemoteViews orig = new RemoteViews("com.android.frameworktest",
+                R.layout.remote_view_test_good);
+        Parcel p = Parcel.obtain();
+        orig.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        
+        RemoteViews r = RemoteViews.CREATOR.createFromParcel(p);
+        
+        ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent);
+        
+        View result = r.apply(activity, parent);
+        
+        p.recycle();
+        
+        assertTrue("LinearLayout not inflated", result.findViewById(R.id.linear) != null);
+        assertTrue("TextView not inflated", result.findViewById(R.id.text) != null);
+        assertTrue("ImageView not inflated", result.findViewById(R.id.image) != null);
+        assertTrue("FrameLayout not inflated", result.findViewById(R.id.frame) != null);
+        assertTrue("RelateiveLayout not inflated", result.findViewById(R.id.relative) != null);
+        assertTrue("AbsoluteLayout not inflated", result.findViewById(R.id.absolute) != null);
+        assertTrue("ProgressBar not inflated", result.findViewById(R.id.progress) != null);
+        assertTrue("ImageButton not inflated", result.findViewById(R.id.image_button) != null);
+        assertTrue("Button not inflated", result.findViewById(R.id.button) != null);
+    }
+    
+    @MediumTest
+    public void testDerivedClass() throws Exception {
+        final RemoteViewsActivity activity = getActivity();
+        
+        RemoteViews orig = new RemoteViews("com.android.frameworktest",
+                R.layout.remote_view_test_bad_1);
+        Parcel p = Parcel.obtain();
+        orig.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        
+        RemoteViews r = RemoteViews.CREATOR.createFromParcel(p);
+        
+        ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent);
+        
+        boolean exceptionThrown = false;
+        View result = null;
+        
+        try {
+            result = r.apply(activity, parent);
+        } catch (InflateException e) {
+            exceptionThrown = true;
+        }
+        
+        p.recycle();
+        
+        assertTrue("Derived class (EditText) allowed to be inflated", exceptionThrown);
+        assertNull("Derived class (EditText) allowed to be inflated", result);
+    }
+    
+    @MediumTest
+    public void testWebView() throws Exception {
+        final RemoteViewsActivity activity = getActivity();
+        
+        RemoteViews orig = new RemoteViews("com.android.frameworktest",
+                R.layout.remote_view_test_bad_2);
+        Parcel p = Parcel.obtain();
+        orig.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        
+        RemoteViews r = RemoteViews.CREATOR.createFromParcel(p);
+        
+        ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent);
+        
+        boolean exceptionThrown = false;
+        View result = null;
+        
+        try {
+            result = r.apply(activity, parent);
+        } catch (InflateException e) {
+            exceptionThrown = true;
+        }
+        
+        p.recycle();
+        
+        assertTrue("WebView allowed to be inflated", exceptionThrown);
+        assertNull("WebView allowed to be inflated", result);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RunQueueTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RunQueueTest.java
new file mode 100644
index 0000000..dc8fcd8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RunQueueTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class RunQueueTest extends ActivityInstrumentationTestCase<RunQueue> {
+    public RunQueueTest() {
+        super("com.android.frameworktest", RunQueue.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @MediumTest
+    public void testRunnableRan() throws Exception {
+        final RunQueue activity = getActivity();
+        getInstrumentation().waitForIdleSync();
+        assertTrue("The runnable did not run", activity.runnableRan);
+    }
+
+    @MediumTest
+    public void testRunnableCancelled() throws Exception {
+        final RunQueue activity = getActivity();
+        getInstrumentation().waitForIdleSync();
+        assertTrue("The runnable was not cancelled", activity.runnableCancelled);
+    }
+
+    @MediumTest
+    public void testListenerFired() throws Exception {
+        final RunQueue activity = getActivity();
+        getInstrumentation().waitForIdleSync();
+        assertTrue("The global layout listener did not fire", activity.globalLayout);
+    }
+
+    @MediumTest
+    public void testTreeObserverKilled() throws Exception {
+        final RunQueue activity = getActivity();
+        getInstrumentation().waitForIdleSync();
+        assertFalse("The view tree observer is still alive", activity.viewTreeObserver.isAlive());
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewGroupChildrenTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewGroupChildrenTest.java
new file mode 100644
index 0000000..fceec51
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewGroupChildrenTest.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.view.ViewGroupChildren;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.test.UiThreadTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Exercises {@link android.view.ViewGroup}'s ability to add/remove children.
+ */
+public class ViewGroupChildrenTest extends ActivityInstrumentationTestCase<ViewGroupChildren> {
+    private ViewGroup mGroup;
+
+    public ViewGroupChildrenTest() {
+        super("com.android.frameworktest", ViewGroupChildren.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final ViewGroupChildren a = getActivity();
+        mGroup = (ViewGroup) a.findViewById(R.id.group);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mGroup);
+    }
+
+    @MediumTest
+    public void testStartsEmpty() throws Exception {
+        assertEquals("A ViewGroup should have no child by default", 0, mGroup.getChildCount());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testAddChild() throws Exception {
+        View view = createView("1");
+        mGroup.addView(view);
+
+        assertEquals(1, mGroup.getChildCount());
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        ViewAsserts.assertGroupContains(mGroup, view);
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testAddChildAtFront() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        for (int i = 0; i < 24; i++) {
+            View view = createView(String.valueOf(i + 1));
+            mGroup.addView(view);
+        }
+
+        View view = createView("X");
+        mGroup.addView(view, 0);
+
+        assertEquals(25, mGroup.getChildCount());
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        ViewAsserts.assertGroupContains(mGroup, view);
+        assertSame(view, mGroup.getChildAt(0));
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testAddChildInMiddle() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        for (int i = 0; i < 24; i++) {
+            View view = createView(String.valueOf(i + 1));
+            mGroup.addView(view);
+        }
+
+        View view = createView("X");
+        mGroup.addView(view, 12);
+
+        assertEquals(25, mGroup.getChildCount());
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        ViewAsserts.assertGroupContains(mGroup, view);
+        assertSame(view, mGroup.getChildAt(12));
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testAddChildren() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        for (int i = 0; i < 24; i++) {
+            View view = createView(String.valueOf(i + 1));
+            mGroup.addView(view);
+
+            ViewAsserts.assertGroupContains(mGroup, view);
+        }
+        assertEquals(24, mGroup.getChildCount());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testRemoveChild() throws Exception {
+        View view = createView("1");
+        mGroup.addView(view);
+
+        ViewAsserts.assertGroupIntegrity(mGroup);
+
+        mGroup.removeView(view);
+
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        ViewAsserts.assertGroupNotContains(mGroup, view);
+
+        assertEquals(0, mGroup.getChildCount());
+        assertNull(view.getParent());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testRemoveChildren() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        final View[] views = new View[24];
+
+        for (int i = 0; i < views.length; i++) {
+            views[i] = createView(String.valueOf(i + 1));
+            mGroup.addView(views[i]);
+        }
+
+        for (int i = views.length - 1; i >= 0; i--) {
+            mGroup.removeViewAt(i);
+            ViewAsserts.assertGroupIntegrity(mGroup);
+            ViewAsserts.assertGroupNotContains(mGroup, views[i]);
+            assertNull(views[i].getParent());
+        }
+
+        assertEquals(0, mGroup.getChildCount());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testRemoveChildrenBulk() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        final View[] views = new View[24];
+
+        for (int i = 0; i < views.length; i++) {
+            views[i] = createView(String.valueOf(i + 1));
+            mGroup.addView(views[i]);
+        }
+
+        mGroup.removeViews(6, 7);
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        for (int i = 6; i < 13; i++) {
+            ViewAsserts.assertGroupNotContains(mGroup, views[i]);
+            assertNull(views[i].getParent());
+        }
+
+        assertEquals(17, mGroup.getChildCount());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testRemoveChildrenBulkAtFront() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        final View[] views = new View[24];
+
+        for (int i = 0; i < views.length; i++) {
+            views[i] = createView(String.valueOf(i + 1));
+            mGroup.addView(views[i]);
+        }
+
+        mGroup.removeViews(0, 7);
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        for (int i = 0; i < 7; i++) {
+            ViewAsserts.assertGroupNotContains(mGroup, views[i]);
+            assertNull(views[i].getParent());
+        }
+
+        assertEquals("8", ((TextView) mGroup.getChildAt(0)).getText());
+        assertEquals(17, mGroup.getChildCount());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testRemoveChildrenBulkAtEnd() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        final View[] views = new View[24];
+
+        for (int i = 0; i < views.length; i++) {
+            views[i] = createView(String.valueOf(i + 1));
+            mGroup.addView(views[i]);
+        }
+
+        mGroup.removeViews(17, 7);
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        for (int i = 17; i < 24; i++) {
+            ViewAsserts.assertGroupNotContains(mGroup, views[i]);
+            assertNull(views[i].getParent());
+        }
+        assertEquals("17", ((TextView) mGroup.getChildAt(mGroup.getChildCount() - 1)).getText());
+        assertEquals(17, mGroup.getChildCount());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testRemoveChildAtFront() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        final View[] views = new View[24];
+
+        for (int i = 0; i < views.length; i++) {
+            views[i] = createView(String.valueOf(i + 1));
+            mGroup.addView(views[i]);
+        }
+
+        mGroup.removeViewAt(0);
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        ViewAsserts.assertGroupNotContains(mGroup, views[0]);
+        assertNull(views[0].getParent());
+
+        assertEquals(views.length - 1, mGroup.getChildCount());
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testRemoveChildInMiddle() throws Exception {
+        // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+        final View[] views = new View[24];
+
+        for (int i = 0; i < views.length; i++) {
+            views[i] = createView(String.valueOf(i + 1));
+            mGroup.addView(views[i]);
+        }
+
+        mGroup.removeViewAt(12);
+        ViewAsserts.assertGroupIntegrity(mGroup);
+        ViewAsserts.assertGroupNotContains(mGroup, views[12]);
+        assertNull(views[12].getParent());
+
+        assertEquals(views.length - 1, mGroup.getChildCount());        
+    }
+
+    private TextView createView(String text) {
+        TextView view = new TextView(getActivity());
+        view.setText(text);
+        view.setLayoutParams(new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.FILL_PARENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT
+        ));
+        return view;
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewStubTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewStubTest.java
new file mode 100644
index 0000000..89bd646
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewStubTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.view.StubbedView;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.UiThreadTest;
+import android.view.View;
+import android.view.ViewStub;
+
+public class ViewStubTest extends ActivityInstrumentationTestCase<StubbedView> {
+    public ViewStubTest() {
+        super("com.android.frameworktest", StubbedView.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @MediumTest
+    public void testStubbed() throws Exception {
+        final StubbedView activity = getActivity();
+
+        final View stub = activity.findViewById(R.id.viewStub);
+        assertNotNull("The ViewStub does not exist", stub);
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testInflated() throws Exception {
+        final StubbedView activity = getActivity();
+
+        final ViewStub stub = (ViewStub) activity.findViewById(R.id.viewStub);
+        final View swapped = stub.inflate();
+
+        assertNotNull("The inflated view is null", swapped);
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testInflatedId() throws Exception {
+        final StubbedView activity = getActivity();
+
+        final ViewStub stub = (ViewStub) activity.findViewById(R.id.viewStubWithId);
+        final View swapped = stub.inflate();
+
+        assertNotNull("The inflated view is null", swapped);
+        assertTrue("The inflated view has no id", swapped.getId() != View.NO_ID);
+        assertTrue("The inflated view has the wrong id", swapped.getId() == R.id.stub_inflated);
+    }
+
+    @UiThreadTest
+    @MediumTest
+    public void testInflatedLayoutParams() throws Exception {
+        final StubbedView activity = getActivity();
+
+        final ViewStub stub = (ViewStub) activity.findViewById(R.id.viewStubWithId);
+        final View swapped = stub.inflate();
+
+        assertNotNull("The inflated view is null", swapped);
+
+        assertEquals("Both stub and inflated should same width",
+                stub.getLayoutParams().width, swapped.getLayoutParams().width);
+        assertEquals("Both stub and inflated should same height",
+                stub.getLayoutParams().height, swapped.getLayoutParams().height);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/VisibilityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/VisibilityTest.java
new file mode 100644
index 0000000..77b281d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/VisibilityTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.view.Visibility;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.TextView;
+import android.view.View;
+import static android.view.KeyEvent.*;
+
+/**
+ * Exercises {@link android.view.View}'s ability to change visibility between
+ * GONE, VISIBLE and INVISIBLE.
+ */
+public class VisibilityTest extends ActivityInstrumentationTestCase<Visibility> {
+    private TextView mRefUp;
+    private TextView mRefDown;
+    private TextView mVictim;
+    private Button mVisible;
+    private Button mInvisible;
+    private Button mGone;
+
+    public VisibilityTest() {
+        super("com.android.frameworktest", Visibility.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final Visibility a = getActivity();
+        mRefUp = (TextView) a.findViewById(R.id.refUp);
+        mRefDown = (TextView) a.findViewById(R.id.refDown);
+        mVictim = (TextView) a.findViewById(R.id.victim);
+        mVisible = (Button) a.findViewById(R.id.vis);
+        mInvisible = (Button) a.findViewById(R.id.invis);
+        mGone = (Button) a.findViewById(R.id.gone);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mRefUp);
+        assertNotNull(mRefDown);
+        assertNotNull(mVictim);
+        assertNotNull(mVisible);
+        assertNotNull(mInvisible);
+        assertNotNull(mGone);
+
+        assertTrue(mVisible.hasFocus());
+    }
+
+    @MediumTest
+    public void testVisibleToInvisible() throws Exception {
+        sendKeys("DPAD_RIGHT");
+        assertTrue(mInvisible.hasFocus());
+
+        int oldTop = mVictim.getTop();
+
+        sendKeys("DPAD_CENTER");
+        assertEquals(View.INVISIBLE, mVictim.getVisibility());
+
+        int newTop = mVictim.getTop();
+        assertEquals(oldTop, newTop);
+    }
+
+    @MediumTest
+    public void testVisibleToGone() throws Exception {
+        //sendKeys("2*DPAD_RIGHT");
+        sendRepeatedKeys(2, KEYCODE_DPAD_RIGHT);
+        assertTrue(mGone.hasFocus());
+
+        int oldTop = mVictim.getTop();
+
+        sendKeys("DPAD_CENTER");
+        assertEquals(View.GONE, mVictim.getVisibility());
+
+        int refDownTop = mRefDown.getTop();
+        assertEquals(oldTop, refDownTop);
+    }
+
+    @LargeTest
+    public void testGoneToVisible() throws Exception {
+        sendKeys("2*DPAD_RIGHT");
+        assertTrue(mGone.hasFocus());
+
+        int oldTop = mVictim.getTop();
+
+        sendKeys("DPAD_CENTER");
+        assertEquals(View.GONE, mVictim.getVisibility());
+
+        int refDownTop = mRefDown.getTop();
+        assertEquals(oldTop, refDownTop);
+
+        sendKeys("2*DPAD_LEFT DPAD_CENTER");
+        assertEquals(View.VISIBLE, mVictim.getVisibility());
+
+        int newTop = mVictim.getTop();
+        assertEquals(oldTop, newTop);
+    }
+
+    @MediumTest
+    public void testGoneToInvisible() throws Exception {
+        sendKeys("2*DPAD_RIGHT");
+        assertTrue(mGone.hasFocus());
+
+        int oldTop = mVictim.getTop();
+
+        sendKeys("DPAD_CENTER");
+        assertEquals(View.GONE, mVictim.getVisibility());
+
+        int refDownTop = mRefDown.getTop();
+        assertEquals(oldTop, refDownTop);
+
+        sendKeys(KEYCODE_DPAD_LEFT, KEYCODE_DPAD_CENTER);
+        assertEquals(View.INVISIBLE, mVictim.getVisibility());
+
+        int newTop = mVictim.getTop();
+        assertEquals(oldTop, newTop);
+    }
+
+    @MediumTest
+    public void testInvisibleToVisible() throws Exception {
+        sendKeys("DPAD_RIGHT");
+        assertTrue(mInvisible.hasFocus());
+
+        int oldTop = mVictim.getTop();
+
+        sendKeys("DPAD_CENTER");
+        assertEquals(View.INVISIBLE, mVictim.getVisibility());
+
+        int newTop = mVictim.getTop();
+        assertEquals(oldTop, newTop);
+
+        sendKeys("DPAD_LEFT DPAD_CENTER");
+        assertEquals(View.VISIBLE, mVictim.getVisibility());
+
+        newTop = mVictim.getTop();
+        assertEquals(oldTop, newTop);
+    }
+
+    @MediumTest
+    public void testInvisibleToGone() throws Exception {
+        sendKeys("DPAD_RIGHT");        
+        assertTrue(mInvisible.hasFocus());
+
+        int oldTop = mVictim.getTop();
+
+        sendKeys("DPAD_CENTER");
+        assertEquals(View.INVISIBLE, mVictim.getVisibility());
+
+        int newTop = mVictim.getTop();
+        assertEquals(oldTop, newTop);
+
+        sendKeys("DPAD_RIGHT DPAD_CENTER");
+        assertEquals(View.GONE, mVictim.getVisibility());
+
+        int refDownTop = mRefDown.getTop();
+        assertEquals(oldTop, refDownTop);
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ZeroSizedTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ZeroSizedTest.java
new file mode 100644
index 0000000..cd646e4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ZeroSizedTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 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.frameworktest.view;
+
+import com.android.frameworktest.view.ZeroSized;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.graphics.Bitmap;
+
+/**
+ * Builds the drawing cache of Views of various dimension. The assumption is that
+ * a View with a 0-sized dimension (width or height) will always have a null
+ * drawing cache.
+ */
+public class ZeroSizedTest extends ActivityInstrumentationTestCase<ZeroSized> {
+    private View mWithDimension;
+    private View mWithNoWdith;
+    private View mWithNoHeight;
+    private View mWithNoDimension;
+
+    public ZeroSizedTest() {
+        super("com.android.frameworktest", ZeroSized.class);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        final ZeroSized activity = getActivity();
+        mWithDimension = activity.findViewById(R.id.dimension);
+        mWithNoWdith = activity.findViewById(R.id.noWidth);
+        mWithNoHeight = activity.findViewById(R.id.noHeight);
+        mWithNoDimension = activity.findViewById(R.id.noDimension);
+    }
+
+    @MediumTest
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mWithDimension);
+        assertNotNull(mWithNoWdith);
+        assertNotNull(mWithNoHeight);
+        assertNotNull(mWithNoDimension);
+    }
+
+    @MediumTest
+    public void testDrawingCacheWithDimension() throws Exception {
+        assertTrue(mWithDimension.getWidth() > 0);
+        assertTrue(mWithDimension.getHeight() > 0);
+        assertNotNull(createCacheForView(mWithDimension));
+    }
+
+    @MediumTest
+    public void testDrawingCacheWithNoWidth() throws Exception {
+        assertTrue(mWithNoWdith.getWidth() == 0);
+        assertTrue(mWithNoWdith.getHeight() > 0);
+        assertNull(createCacheForView(mWithNoWdith));
+    }
+
+    @MediumTest
+    public void testDrawingCacheWithNoHeight() throws Exception {
+        assertTrue(mWithNoHeight.getWidth() > 0);
+        assertTrue(mWithNoHeight.getHeight() == 0);
+        assertNull(createCacheForView(mWithNoHeight));
+    }
+
+    @MediumTest
+    public void testDrawingCacheWithNoDimension() throws Exception {
+        assertTrue(mWithNoDimension.getWidth() == 0);
+        assertTrue(mWithNoDimension.getHeight() == 0);
+        assertNull(createCacheForView(mWithNoDimension));
+    }
+
+    private Bitmap createCacheForView(final View view) {
+        final Bitmap[] cache = new Bitmap[1];
+        getActivity().runOnUiThread(new Runnable() {
+            public void run() {
+                view.setDrawingCacheEnabled(true);
+                view.invalidate();
+                view.buildDrawingCache();
+                cache[0] = view.getDrawingCache();
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        return cache[0];
+    }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java
new file mode 100644
index 0000000..ecb7d3a
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java
@@ -0,0 +1,139 @@
+package com.android.frameworktest.widget;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Assert;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.test.InstrumentationTestCase;
+import android.test.mock.MockContext;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import java.util.List;
+
+/**
+ * Copyright (C) 2007 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.
+ */
+
+public class ListViewTest extends InstrumentationTestCase {
+
+    /**
+     * If a view in a ListView requests a layout it should be remeasured.
+     */
+    @MediumTest
+    public void testRequestLayout() throws Exception {
+        MockContext context = new MockContext2();
+        ListView listView = new ListView(context);
+        List<String> items = Lists.newArrayList("hello");
+        Adapter<String> adapter = new Adapter<String>(context, 0, items);
+        listView.setAdapter(adapter);
+
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
+
+        adapter.notifyDataSetChanged();
+        listView.measure(measureSpec, measureSpec);
+        listView.layout(0, 0, 100, 100);
+
+        MockView childView = (MockView) listView.getChildAt(0);
+
+        childView.requestLayout();
+        childView.onMeasureCalled = false;
+        listView.measure(measureSpec, measureSpec);
+        listView.layout(0, 0, 100, 100);
+        Assert.assertTrue(childView.onMeasureCalled);
+    }
+
+    /**
+     * The list view should handle the disappearance of the only selected item, even when that item
+     * was selected before its disappearance.
+     *
+     */
+    @MediumTest
+    public void testNoSelectableItems() throws Exception {
+        MockContext context = new MockContext2();
+        ListView listView = new ListView(context);
+        // We use a header as the unselectable item to remain after the selectable one is removed.
+        listView.addHeaderView(new View(context), null, false);
+        List<String> items = Lists.newArrayList("hello");
+        Adapter<String> adapter = new Adapter<String>(context, 0, items);
+        listView.setAdapter(adapter);
+
+        listView.setSelection(1);
+
+        int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
+
+        adapter.notifyDataSetChanged();
+        listView.measure(measureSpec, measureSpec);
+        listView.layout(0, 0, 100, 100);
+
+        items.remove(0);
+
+        adapter.notifyDataSetChanged();
+        listView.measure(measureSpec, measureSpec);
+        listView.layout(0, 0, 100, 100);
+    }
+
+    private class MockContext2 extends MockContext {
+
+        @Override
+        public Resources getResources() {
+            return getInstrumentation().getTargetContext().getResources();
+        }
+
+        @Override
+        public Resources.Theme getTheme() {
+            return getInstrumentation().getTargetContext().getTheme();
+        }
+
+        @Override
+        public Object getSystemService(String name) {
+            if (Context.LAYOUT_INFLATER_SERVICE.equals(name)) {
+                return getInstrumentation().getTargetContext().getSystemService(name);
+            }
+            return super.getSystemService(name);
+        }
+    }
+    
+    private class MockView extends View {
+
+        public boolean onMeasureCalled = false;
+
+        public MockView(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            onMeasureCalled = true;
+        }
+    }
+
+    private class Adapter<T> extends ArrayAdapter<T> {
+
+        public Adapter(Context context, int resource, List<T> objects) {
+            super(context, resource, objects);
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            return new MockView(getContext());
+        }
+    }
+
+}
diff --git a/tests/ImfTest/Android.mk b/tests/ImfTest/Android.mk
new file mode 100755
index 0000000..eb5327b
--- /dev/null
+++ b/tests/ImfTest/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := ImfTest
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/ImfTest/AndroidManifest.xml b/tests/ImfTest/AndroidManifest.xml
new file mode 100755
index 0000000..55e5d38
--- /dev/null
+++ b/tests/ImfTest/AndroidManifest.xml
@@ -0,0 +1,144 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
+        package="com.android.imftest">
+
+   <application>
+    
+        <activity android:name=".samples.InputTypeActivity" android:label="Input Type Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+                
+        <activity android:name=".samples.ButtonActivity" android:label="Button Activity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".samples.BigEditTextActivityNonScrollablePanScan" android:label="Big ET !Scroll Pan/Scan">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".samples.ManyEditTextActivityNoScrollPanScan" android:label="ManyEditTextActivityNoScrollPanScan">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".samples.BigEditTextActivityNonScrollableResize" android:label="Big ET !Scroll Resize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".samples.BigEditTextActivityScrollablePanScan" android:label="Big ET Scroll Pan/Scan">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".samples.BigEditTextActivityScrollableResize" android:label="Big ET Scroll Resize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".samples.EditTextActivityDialog" android:label="ET Dialog">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".samples.ManyEditTextActivityScrollPanScan" android:label="ManyEditTextActivityScrollPanScan">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".samples.ManyEditTextActivityScrollResize" android:label="ManyEditTextActivityScrollResize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".samples.BottomEditTextActivityPanScan" android:label="BottomEditTextActivityPanScan">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".samples.BottomEditTextActivityResize" android:label="BottomEditTextActivityResize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+        
+        <activity android:name=".samples.OneEditTextActivitySelected" android:label="OneEditTextActivitySelected">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+    
+        <activity android:name=".samples.OneEditTextActivityNotSelected" android:label="OneEditTextActivityNotSelected">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+         
+        <activity android:name=".samples.AutoCompleteTextViewActivityPortrait" android:label="AutoCompleteTextViewActivityPortrait" android:screenOrientation="portrait">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>
+   
+        <activity android:name=".samples.AutoCompleteTextViewActivityLandscape" android:label="AutoCompleteTextViewActivityLandscape" android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>   
+        
+        <activity android:name=".samples.DialogActivity" android:label="DialogActivity" android:screenOrientation="portrait">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="android.intent.category.IMF_TEST" />
+            </intent-filter>
+        </activity>              
+          
+    </application>
+    
+</manifest>
diff --git a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
new file mode 100644
index 0000000..e8ffa1c
--- /dev/null
+++ b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:padding="20dip"
+    android:orientation="vertical">
+            
+    <View
+    	android:id="@+id/blank"
+    	android:layout_height="0dip"
+    	android:layout_width="fill_parent"
+    	android:layout_weight="1"/>
+    	
+    <EditText
+        android:id="@+id/dialog_edit_text"
+        android:layout_height="wrap_content"
+        android:layout_width="fill_parent"
+        android:scrollHorizontally="true"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
diff --git a/tests/ImfTest/res/layout/full_screen_edit_text.xml b/tests/ImfTest/res/layout/full_screen_edit_text.xml
new file mode 100755
index 0000000..f22aa2f
--- /dev/null
+++ b/tests/ImfTest/res/layout/full_screen_edit_text.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2009, 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.
+*/
+-->
+
+<EditText xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/data" 
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:minLines="15"
+    android:gravity="top"/>
+
diff --git a/tests/ImfTest/res/layout/one_edit_text_activity.xml b/tests/ImfTest/res/layout/one_edit_text_activity.xml
new file mode 100755
index 0000000..09925e1
--- /dev/null
+++ b/tests/ImfTest/res/layout/one_edit_text_activity.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+>
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:orientation="vertical"
+        android:baselineAligned="false">
+
+        <View android:id="@+id/blank"
+            android:layout_height="0dip"
+            android:layout_width="fill_parent"
+            android:layout_weight="1"
+        />
+
+        <EditText android:id="@+id/dialog_edit_text"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"
+            android:scrollHorizontally="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+        />
+    </LinearLayout>
+
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="1dip"
+        android:background="@android:drawable/divider_horizontal_dark"
+    />
+</LinearLayout>
diff --git a/tests/ImfTest/res/layout/sample_edit_text.xml b/tests/ImfTest/res/layout/sample_edit_text.xml
new file mode 100755
index 0000000..99a5cf8
--- /dev/null
+++ b/tests/ImfTest/res/layout/sample_edit_text.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, 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.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+>
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="?android:attr/listPreferredItemHeight"
+        android:orientation="horizontal"
+        android:baselineAligned="false"
+        android:gravity="center_vertical"
+    >
+
+        <TextView android:id="@+id/label"
+            android:layout_width="100dip"
+            android:layout_height="wrap_content"
+            android:gravity="right|center_vertical"
+        />
+
+        <EditText android:id="@+id/data"
+            android:layout_width="0dip"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="8dip"
+        />
+    </LinearLayout>
+
+    <View
+        android:layout_width="fill_parent"
+        android:layout_height="1dip"
+        android:background="@android:drawable/divider_horizontal_dark"
+    />
+</LinearLayout>
diff --git a/tests/ImfTest/res/values/config.xml b/tests/ImfTest/res/values/config.xml
new file mode 100644
index 0000000..5ae40a3
--- /dev/null
+++ b/tests/ImfTest/res/values/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); 
+ * you may not use this file except in compliance with the License. 
+ * You may obtain a copy of the License at 
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0 
+ *
+ * Unless required by applicable law or agreed to in writing, software 
+ * distributed under the License is distributed on an "AS IS" BASIS, 
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+ * See the License for the specific language governing permissions and 
+ * limitations under the License.
+ */
+-->
+<resources>
+    <bool name="def_expect_ime_autopop">false</bool>
+</resources>
diff --git a/tests/ImfTest/res/values/strings.xml b/tests/ImfTest/res/values/strings.xml
new file mode 100755
index 0000000..fc87480
--- /dev/null
+++ b/tests/ImfTest/res/values/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Strings for sample activities -->
+    <string name="normal_edit_text_label">Normal</string>
+    <string name="uri_edit_text_label">Uri</string>
+    <string name="email_address_edit_text_label">Email Address</string>
+    <string name="email_subject_edit_text_label">Email Subject</string>
+    <string name="email_content_edit_text_label">Email Content</string>
+    <string name="person_name_edit_text_label">Person Name</string>
+    <string name="postal_address_edit_text_label">Postal Address</string>
+    <string name="password_edit_text_label">Password</string>
+    <string name="search_string_edit_text_label">Search String</string>
+    <string name="web_edit_text_label">Web Edit Text</string>
+    <string name="signed_number_edit_text_label">Signed Number</string>
+    <string name="decimal_number_edit_text_label">Decimal Number</string>
+    <string name="phone_number_edit_text_label">Phone Number</string>
+    <string name="normal_datetime_edit_text_label">Datetime</string>
+    <string name="date_edit_text_label">Date</string>
+    <string name="time_edit_text_label">Time</string>
+    <string name="cap_chars_edit_text_label">Cap Chars</string>
+    <string name="cap_words_edit_text_label">Cap Words</string>
+    <string name="multiline_edit_text_label">Multiline</string>
+    <string name="search_edit_text_label">Search (flag)</string>
+    <string name="cap_sentences_edit_text_label">Cap Sentences</string>
+    <string name="auto_complete_edit_text_label">Auto Complete</string>
+    <string name="auto_correct_edit_text_label">Auto Correct</string>
+    <string name="test_dialog">Test Dialog</string>
+    <string name="open_dialog_scrollable">open scrollable dialog</string>
+    <string name="open_dialog_nonscrollable">open nonscrollable dialog</string>
+    
+    
+</resources>
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
new file mode 100644
index 0000000..9638d34a
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
@@ -0,0 +1,85 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.MediaStore;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.AutoCompleteTextView;
+import android.widget.ArrayAdapter;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+
+import com.android.internal.R;
+
+/*
+ * Activity with AutoCompleteTextView forced to landscape mode
+ */
+public class AutoCompleteTextViewActivityLandscape extends Activity 
+{
+   @Override
+   public void onCreate(Bundle savedInstanceState) 
+   {
+       super.onCreate(savedInstanceState);
+    
+       setContentView(R.layout.auto_complete_list);
+
+       ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
+               android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+       AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.edit);
+       textView.setAdapter(adapter);
+   }
+
+   static final String[] COUNTRIES = new String[] {
+   "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+   "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+   "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+   "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+   "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+   "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
+   "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
+   "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+   "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+   "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+   "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+   "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+   "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+   "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+   "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+   "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+   "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+   "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+   "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+   "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+   "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+   "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+   "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+   "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+   "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+   "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+   "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+   "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+   "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+   "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+   "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+   "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+   "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+   "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+   "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+   "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+   "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+   "Ukraine", "United Arab Emirates", "United Kingdom",
+   "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+   "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+   "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+   };
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
new file mode 100644
index 0000000..58651e1
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
@@ -0,0 +1,79 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.AutoCompleteTextView;
+import android.widget.ArrayAdapter;
+
+import com.android.internal.R;
+
+/*
+ * Activity with AutoCompleteTextView (Candidate bar should not appear)
+ */
+public class AutoCompleteTextViewActivityPortrait extends Activity 
+{
+   @Override
+   public void onCreate(Bundle savedInstanceState) 
+   {
+       super.onCreate(savedInstanceState);
+       
+       setContentView(R.layout.auto_complete_list);
+
+       ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, 
+               android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+       AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.edit);
+       textView.setAdapter(adapter);
+   }
+
+   static final String[] COUNTRIES = new String[] {
+   "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+   "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+   "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+   "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+   "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+   "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
+   "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
+   "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+   "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+   "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+   "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+   "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+   "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+   "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+   "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+   "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+   "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+   "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+   "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+   "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+   "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+   "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+   "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+   "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+   "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+   "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+   "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+   "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+   "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+   "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+   "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+   "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+   "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+   "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+   "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+   "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+   "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+   "Ukraine", "United Arab Emirates", "United Kingdom",
+   "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+   "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+   "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+   };
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
new file mode 100644
index 0000000..9754381
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
@@ -0,0 +1,49 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityNonScrollablePanScan extends Activity {
+    
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+        
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        View view = getLayoutInflater().inflate(
+                R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
+        
+        ((LinearLayout) mRootView).addView(view);
+        
+        mDefaultFocusedView = view.findViewById(R.id.data);
+        
+        setContentView(mRootView);
+    }
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
new file mode 100644
index 0000000..701795f
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
@@ -0,0 +1,49 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityNonScrollableResize extends Activity {
+    
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+        
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        View view = getLayoutInflater().inflate(
+                R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
+        
+        ((LinearLayout) mRootView).addView(view);
+        
+        mDefaultFocusedView = view.findViewById(R.id.data);
+        
+        setContentView(mRootView);
+    }
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
new file mode 100644
index 0000000..bb3f767
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
@@ -0,0 +1,57 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityScrollablePanScan extends Activity {
+    
+    private View mRootView;
+    private View mDefaultFocusedView;
+    private LinearLayout mLayout;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+        
+        mRootView = new ScrollView(this);
+        ((ScrollView) mRootView).setFillViewport(true);
+        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        View view = getLayoutInflater().inflate(
+                R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
+        
+        mLayout.addView(view);
+        
+        ((ScrollView) mRootView).addView(mLayout);
+        mDefaultFocusedView = view.findViewById(R.id.data);
+        
+        setContentView(mRootView);
+    }
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
new file mode 100644
index 0000000..f2cae1c
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
@@ -0,0 +1,57 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityScrollableResize extends Activity {
+    
+    private View mRootView;
+    private View mDefaultFocusedView;
+    private LinearLayout mLayout;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+        
+        mRootView = new ScrollView(this);
+        ((ScrollView) mRootView).setFillViewport(true);
+        mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        View view = getLayoutInflater().inflate(
+                R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
+        
+        mLayout.addView(view);
+        
+        ((ScrollView) mRootView).addView(mLayout);
+        mDefaultFocusedView = view.findViewById(R.id.data);
+        
+        setContentView(mRootView);
+    }
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
new file mode 100644
index 0000000..51f5045
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
@@ -0,0 +1,46 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.imftest.R;
+
+/*
+ * Activity with EditText at the bottom (Pan&Scan)
+ */
+public class BottomEditTextActivityPanScan extends Activity 
+{
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+        
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+        
+        View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
+        mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
+        ((LinearLayout) mRootView).addView(view);
+       
+        setContentView(mRootView);
+        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+    }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+}
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
new file mode 100644
index 0000000..eb94b4f
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
@@ -0,0 +1,46 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.imftest.R;
+
+/*
+ * Activity with EditText at the bottom (Resize)
+ */
+public class BottomEditTextActivityResize extends Activity 
+{
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+        
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+        
+        View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
+        mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
+        ((LinearLayout) mRootView).addView(view);
+       
+        setContentView(mRootView);
+        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+    }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+}
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
new file mode 100644
index 0000000..1191f19
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
@@ -0,0 +1,62 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+
+public class ButtonActivity extends Activity 
+{
+    static boolean mKeyboardIsActive = false;
+    public static final int BUTTON_ID = 0;
+    private View mRootView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+        final ButtonActivity instance = this;
+             
+        final Button myButton = new Button(this);
+        myButton.setClickable(true);
+        myButton.setText("Keyboard UP!");
+        myButton.setId(BUTTON_ID);
+        myButton.setFocusableInTouchMode(true);
+        myButton.setOnClickListener(new View.OnClickListener()
+        {
+            public void onClick (View v)
+            {
+                InputMethodManager imm = InputMethodManager.getInstance(instance);
+                if (mKeyboardIsActive)
+                {
+                    imm.hideSoftInputFromInputMethod(v.getWindowToken(), 0);
+                    myButton.setText("Keyboard UP!");
+            
+                }
+                else
+                {
+                    myButton.requestFocusFromTouch();
+                    imm.showSoftInput(v, 0);
+                    myButton.setText("Keyboard DOWN!");
+                }
+               
+                mKeyboardIsActive = !mKeyboardIsActive;
+            }
+        });
+            
+       LinearLayout layout = new LinearLayout(this);
+       layout.setOrientation(LinearLayout.VERTICAL);
+       layout.addView(myButton);
+       setContentView(layout);
+       mRootView = layout;
+    }
+    
+    public View getRootView() {
+        return mRootView;
+    }
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
new file mode 100644
index 0000000..e49301c
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
@@ -0,0 +1,102 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.Button;
+import android.view.LayoutInflater;
+import android.app.Dialog;
+
+import com.android.internal.R;
+
+public class DialogActivity extends Activity {
+
+    private static final int DIALOG_WITHOUT_EDITTEXT = 0;
+    private static final int DIALOG_WITH_EDITTEXT = 1;
+
+    private LinearLayout mLayout;
+    private LayoutInflater mInflater;
+    private Button mButton1;
+    private Button mButton2;
+    private EditText mEditText;
+
+
+    @Override
+    protected void onCreate(Bundle icicle) 
+    {
+        super.onCreate(icicle);
+
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+        mButton1 = new Button(this);
+        mButton1.setText("Dialog WITHOUT EditText");//(R.string.open_dialog_scrollable);
+        mButton1.setOnClickListener(new View.OnClickListener() 
+        {
+            public void onClick(View v) 
+            {
+                showDialog(DIALOG_WITHOUT_EDITTEXT);
+            }
+        });
+
+        mButton2 = new Button(this);
+        mButton2.setText("Dialog WITH EditText");//(R.string.open_dialog_nonscrollable);
+        mButton2.setOnClickListener(new View.OnClickListener() 
+        {
+            public void onClick(View v) 
+            {
+                showDialog(DIALOG_WITH_EDITTEXT);
+            }
+        });
+
+        mEditText = new EditText(this);
+        mLayout.addView(mEditText);
+        mLayout.addView(mButton1);
+        mLayout.addView(mButton2);
+
+        setContentView(mLayout);
+    }
+
+    @Override
+    protected Dialog onCreateDialog(int id) 
+    {
+        switch (id) 
+        {
+            case DIALOG_WITHOUT_EDITTEXT:
+                return createDialog(false);
+            case DIALOG_WITH_EDITTEXT:
+                return createDialog(true);
+        }
+
+        return super.onCreateDialog(id);
+    }
+
+    protected Dialog createDialog(boolean bEditText) 
+    {
+        LinearLayout layout;        
+        layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+        
+        if(bEditText)
+        {
+            EditText editText;
+            editText = new EditText(this);
+            layout.addView(editText);
+        }
+        
+        Dialog d = new Dialog(this);
+        d.setTitle("The DIALOG!!!");
+        d.setCancelable(true);
+        d.setContentView(layout);
+        return d;
+    }
+
+ }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
new file mode 100644
index 0000000..bd1e934
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
@@ -0,0 +1,96 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class EditTextActivityDialog extends Activity {
+    
+    private static final int SCROLLABLE_DIALOG_ID = 0;
+    private static final int NONSCROLLABLE_DIALOG_ID = 1;
+    
+    private LinearLayout mLayout;
+    private ScrollView mScrollView;
+    private LayoutInflater mInflater;
+    private Button mButton1;
+    private Button mButton2;
+    
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+        
+        mButton1 = new Button(this);
+        mButton1.setText(R.string.open_dialog_scrollable);
+        mButton1.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                showDialog(SCROLLABLE_DIALOG_ID);
+            }
+        });
+        
+        mButton2 = new Button(this);
+        mButton2.setText(R.string.open_dialog_nonscrollable);
+        mButton2.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                showDialog(NONSCROLLABLE_DIALOG_ID);
+            }
+        });
+        
+        mLayout.addView(mButton1);
+        mLayout.addView(mButton2);
+        
+        setContentView(mLayout);
+    }
+    
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        switch (id) {
+            case SCROLLABLE_DIALOG_ID:
+                return createDialog(true);
+            case NONSCROLLABLE_DIALOG_ID:
+                return createDialog(false);
+        }
+
+        return super.onCreateDialog(id);
+    }
+    
+    protected Dialog createDialog(boolean scrollable) {
+        View layout;
+        EditText editText;
+        
+        if (scrollable) {
+            layout = new ScrollView(EditTextActivityDialog.this);
+            ((ScrollView) layout).setMinimumHeight(mLayout.getHeight());
+            
+            ((ScrollView) layout).addView((
+                    LinearLayout) View.inflate(EditTextActivityDialog.this, 
+                    R.layout.dialog_edit_text_no_scroll, null));
+        } else {
+            layout = View.inflate(EditTextActivityDialog.this, 
+                    R.layout.dialog_edit_text_no_scroll, null);
+        }
+        
+        Dialog d = new Dialog(EditTextActivityDialog.this);
+        d.setTitle(getString(R.string.test_dialog));
+        d.setCancelable(true);
+        d.setContentView(layout);
+        return d;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
new file mode 100755
index 0000000..17f6bdc
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewRoot;
+import android.view.inputmethod.EditorInfo;
+import android.content.Context;
+
+public class InputTypeActivity extends Activity {
+
+    private LinearLayout mLayout;
+    private ScrollView mScrollView;
+    private LayoutInflater mInflater;
+    private ViewGroup mParent;
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mScrollView = new ScrollView(this);
+        
+        mLayout = new LinearLayout(this);
+        mLayout.setOrientation(LinearLayout.VERTICAL);
+        mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.FILL_PARENT,
+                ViewGroup.LayoutParams.FILL_PARENT));
+
+        mInflater = getLayoutInflater();
+        mParent = mLayout;
+        
+        /* Normal Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL, 
+                R.string.normal_edit_text_label));
+        
+        /* Normal Edit Text w/Cap Chars Flag*/
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS, 
+                R.string.cap_chars_edit_text_label));
+        
+        /* Normal Edit Text w/Cap Words Flag*/
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS, 
+                R.string.cap_words_edit_text_label));
+        
+        /* Normal Edit Text w/Cap Multiline Flag */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE, 
+                R.string.multiline_edit_text_label));
+        
+        /* Normal Edit Text w/Cap Sentences Flag */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES, 
+                R.string.cap_sentences_edit_text_label));
+        
+        /* Normal Edit Text w/Auto-complete Flag */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE, 
+                R.string.auto_complete_edit_text_label));
+        
+        /* Normal Edit Text w/Auto-correct Flag */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT, 
+                R.string.auto_correct_edit_text_label));
+        
+        /* Uri Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_URI, 
+        		R.string.uri_edit_text_label));
+        
+        /* Email Address Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS, 
+        		R.string.email_address_edit_text_label));
+        
+        /* Email Subject Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT, 
+                R.string.email_subject_edit_text_label));
+        
+        /* Email Content Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_LONG_MESSAGE, 
+                R.string.email_content_edit_text_label));
+        
+        /* Person Name Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME, 
+                R.string.person_name_edit_text_label));
+        
+        /* Postal Address Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS, 
+                R.string.postal_address_edit_text_label));
+        
+        /* Password Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PASSWORD, 
+                R.string.password_edit_text_label));
+        
+        /* Web Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT, 
+                R.string.web_edit_text_label));
+        
+        /* Signed Number Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_SIGNED, 
+                R.string.signed_number_edit_text_label));
+        
+        /* Decimal Number Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_DECIMAL, 
+                R.string.decimal_number_edit_text_label));
+        
+        /* Phone Number Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_PHONE, 
+                R.string.phone_number_edit_text_label));
+        
+        /* Normal Datetime Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_NORMAL, 
+                R.string.normal_datetime_edit_text_label));
+        
+        /* Date Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_DATE, 
+                R.string.date_edit_text_label));
+        
+        /* Time Edit Text */
+        mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_TIME, 
+                R.string.time_edit_text_label));
+            
+        mScrollView.addView(mLayout);
+        setContentView(mScrollView);
+    }
+    
+    private View buildEntryView(int inputType, int label) {
+
+        
+    	View view = mInflater.inflate(R.layout.sample_edit_text, mParent, false);
+        
+        EditText editText = (EditText) view.findViewById(R.id.data);
+        editText.setInputType(inputType);
+        
+        TextView textView = (TextView) view.findViewById(R.id.label);
+        textView.setText(label);
+        
+        return view;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
new file mode 100644
index 0000000..54ab57a
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
@@ -0,0 +1,50 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Full screen of EditTexts (Non-Scrollable, Pan&Scan)
+ */
+public class ManyEditTextActivityNoScrollPanScan extends Activity 
+{
+    public static final int NUM_EDIT_TEXTS = 9;
+
+    private View mRootView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+
+        mRootView = new LinearLayout(this);
+        ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+
+        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
+        {
+            final EditText editText = new EditText(this);
+            editText.setText(String.valueOf(i));
+            editText.setId(i);
+            ((LinearLayout) mRootView).addView(editText);
+        }
+        setContentView(mRootView);
+        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+    }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
new file mode 100644
index 0000000..b228d34
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
@@ -0,0 +1,52 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Full screen of EditTexts (Scrollable, Pan&Scan)
+ */
+public class ManyEditTextActivityScrollPanScan extends Activity 
+{
+    public static final int NUM_EDIT_TEXTS = 12;
+
+    private View mRootView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+        mRootView = new ScrollView(this);
+
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+
+        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
+        {
+            final EditText editText = new EditText(this);
+            editText.setText(String.valueOf(i));
+            editText.setId(i);
+            layout.addView(editText);
+        }
+
+        ((ScrollView) mRootView).addView(layout);
+        setContentView(mRootView);
+        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+    }   
+
+    public View getRootView() {
+        return mRootView;
+    }
+}
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
new file mode 100644
index 0000000..777fbae
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
@@ -0,0 +1,45 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+
+/*
+ * Full screen of EditTexts (Scrollable, Resize)
+ */
+public class ManyEditTextActivityScrollResize extends Activity 
+{
+    public static final int NUM_EDIT_TEXTS = 12;
+    
+    private View mRootView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+        mRootView = new ScrollView(this);
+       
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+       
+        for (int i=0; i<NUM_EDIT_TEXTS; i++) 
+        {
+            final EditText editText = new EditText(this);
+            editText.setText(String.valueOf(i));
+            editText.setId(i);
+            layout.addView(editText);
+        }
+
+        ((ScrollView) mRootView).addView(layout);
+        setContentView(mRootView);
+        this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+    }  
+
+    public View getRootView() {
+        return mRootView;
+    } 
+}
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
new file mode 100644
index 0000000..88a3447
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
@@ -0,0 +1,56 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Debug;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Activity with non-EditText view selected initially
+ */
+public class OneEditTextActivityNotSelected extends Activity 
+{
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+        mRootView = new ScrollView(this);
+
+        EditText editText = new EditText(this);
+        Button button = new Button(this);
+        button.setText("The focus is here.");
+        button.setFocusableInTouchMode(true);
+        button.requestFocus();
+        mDefaultFocusedView = button;
+        layout.addView(button);
+        layout.addView(editText);
+
+        ((ScrollView) mRootView).addView(layout);
+        setContentView(mRootView);
+    }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
new file mode 100644
index 0000000..1b80263
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
@@ -0,0 +1,51 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Activity with EditText selected initially
+ */
+public class OneEditTextActivitySelected extends Activity 
+{
+    private View mRootView;
+    private View mDefaultFocusedView;
+    
+    @Override
+    public void onCreate(Bundle savedInstanceState) 
+    {
+        super.onCreate(savedInstanceState);
+
+        LinearLayout layout = new LinearLayout(this);
+        layout.setOrientation(LinearLayout.VERTICAL);
+        mRootView = new ScrollView(this);
+        
+        EditText editText = new EditText(this);
+        editText.requestFocus();
+        mDefaultFocusedView = editText;
+        layout.addView(editText);
+
+        ((ScrollView) mRootView).addView(layout);
+        setContentView(mRootView);
+    }  
+
+    public View getRootView() {
+        return mRootView;
+    }
+    
+    public View getDefaultFocusedView() {
+        return mDefaultFocusedView;
+    }
+}
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
new file mode 100755
index 0000000..0f1924c
--- /dev/null
+++ b/tests/ImfTest/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := ImfTestTests
+
+LOCAL_INSTRUMENTATION_FOR := ImfTest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/AndroidManifest.xml b/tests/ImfTest/tests/AndroidManifest.xml
new file mode 100755
index 0000000..122d202
--- /dev/null
+++ b/tests/ImfTest/tests/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.imftest.tests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--
+    This declares that this app uses the instrumentation test runner targeting
+    the package of com.android.imftest.  To run the tests use the command:
+    "adb shell am instrument -w com.android.imftest.tests/android.test.InstrumentationTestRunner"
+    -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.imftest"
+                     android:label="imf tests"/>
+
+</manifest>
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
new file mode 100755
index 0000000..a1c5fd2
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityNonScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityNonScrollablePanScan> {
+
+	public final String TAG = "BigEditTextActivityNonScrollablePanScanTests";
+	
+    public BigEditTextActivityNonScrollablePanScanTests() {
+        super(BigEditTextActivityNonScrollablePanScan.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {
+	    // Give the IME 2 seconds to appear.
+	    pause(2000);
+        
+	    View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView();
+	    View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView();
+	        
+	    assertNotNull(rootView);
+	    assertNotNull(servedView);
+	    
+	    destructiveCheckImeInitialState(rootView, servedView);
+	    
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
new file mode 100755
index 0000000..2e0b0eb
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityNonScrollableResize> {
+
+	public final String TAG = "BigEditTextActivityNonScrollableResizeTests";
+	
+    public BigEditTextActivityNonScrollableResizeTests() {
+        super(BigEditTextActivityNonScrollableResize.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {       // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getRootView();
+        View servedView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getDefaultFocusedView();
+         
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+            
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
new file mode 100755
index 0000000..d3eefb5
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityScrollablePanScan> {
+
+	public final String TAG = "BigEditTextActivityScrollablePanScanTests";
+	
+    public BigEditTextActivityScrollablePanScanTests() {
+        super(BigEditTextActivityScrollablePanScan.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {       // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getRootView();
+        View servedView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getDefaultFocusedView();
+         
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+            
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
new file mode 100755
index 0000000..5c40e6d
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityScrollableResize> {
+
+	public final String TAG = "BigEditTextActivityScrollableResizeTests";
+	
+    public BigEditTextActivityScrollableResizeTests() {
+        super(BigEditTextActivityScrollableResize.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {       
+	    // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BigEditTextActivityScrollableResize) mTargetActivity).getRootView();
+        View servedView = ((BigEditTextActivityScrollableResize) mTargetActivity).getDefaultFocusedView();
+          
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+            
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
new file mode 100755
index 0000000..9a93133
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEditTextActivityPanScan> {
+
+	public final String TAG = "BottomEditTextActivityPanScanTests";
+	
+    public BottomEditTextActivityPanScanTests() {
+        super(BottomEditTextActivityPanScan.class);
+    }
+	
+	@LargeTest
+	public void testAppAdjustmentPanScan() {
+        // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BottomEditTextActivityPanScan) mTargetActivity).getRootView();
+        View servedView = ((BottomEditTextActivityPanScan) mTargetActivity).getDefaultFocusedView();
+        
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+        
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
new file mode 100755
index 0000000..9a69fd5
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BottomEditTextActivityResizeTests extends ImfBaseTestCase<BottomEditTextActivityResize> {
+
+    public final String TAG = "BottomEditTextActivityResizeTests";
+    
+    public BottomEditTextActivityResizeTests() {
+        super(BottomEditTextActivityResize.class);
+    }
+    
+    @LargeTest
+    public void testAppAdjustmentResize() {
+        // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        View rootView = ((BottomEditTextActivityResize) mTargetActivity).getRootView();
+        View servedView = ((BottomEditTextActivityResize) mTargetActivity).getDefaultFocusedView();
+        
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+        
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+    }
+    
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
new file mode 100755
index 0000000..ae900c3
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+
+public class ButtonActivityTest extends ImfBaseTestCase<ButtonActivity> {
+
+	final public String TAG = "ButtonActivityTest";
+	
+    public ButtonActivityTest() {
+        super(ButtonActivity.class);
+    }
+
+    @LargeTest
+    public void testButtonActivatesIme() {
+       
+        final Button button = (Button) mTargetActivity.findViewById(ButtonActivity.BUTTON_ID);
+        
+        // Push button
+        // Bring the target EditText into focus.
+        mTargetActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                button.requestFocus();
+            }
+        });
+        
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+        
+        // Give it a couple seconds
+        pause(2000);
+        
+        // We should have initialized imm.mServedView and imm.mCurrentTextBoxAttribute
+        assertTrue(mImm.isActive());
+        // imm.mServedInputConnection should be null since Button doesn't override onCreateInputConnection().
+        assertFalse(mImm.isAcceptingText());
+        
+        destructiveCheckImeInitialState(mTargetActivity.getRootView(), button);
+        
+    }
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
new file mode 100755
index 0000000..61dc611
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.app.Activity;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.imftest.R;
+
+public abstract class ImfBaseTestCase<T extends Activity> extends InstrumentationTestCase {
+
+    /*
+     * The amount of time we are willing to wait for the IME to appear after a user action
+     * before we give up and fail the test.
+     */
+    public final long WAIT_FOR_IME = 5000;
+
+    /*
+     * Unfortunately there is now way for us to know how tall the IME is, 
+     * so we have to hard code a minimum and maximum value.
+     */
+    public final int IME_MIN_HEIGHT = 150;
+    public final int IME_MAX_HEIGHT = 300;
+
+    public final String TARGET_PACKAGE_NAME = "com.android.imftest";
+    protected InputMethodManager mImm;
+    protected T mTargetActivity;
+    protected boolean mExpectAutoPop;
+    private Class<T> mTargetActivityClass;
+    
+    public ImfBaseTestCase(Class<T> activityClass) {
+        mTargetActivityClass = activityClass;
+    }
+    
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        mTargetActivity = launchActivity(TARGET_PACKAGE_NAME, mTargetActivityClass, null);
+        mExpectAutoPop = mTargetActivity.getResources().getBoolean(R.bool.def_expect_ime_autopop);
+        mImm = InputMethodManager.getInstance(mTargetActivity);
+    }
+    
+    // Utility test methods
+    public void verifyEditTextAdjustment(final View editText, int rootViewHeight) {
+
+        int[] origLocation = new int[2];
+        int[] newLocation = new int[2];
+
+        // Tell the keyboard to go away.
+        mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
+
+        // Bring the target EditText into focus.
+        mTargetActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                editText.requestFocus();
+            }
+        });
+
+        // Get the original location of the EditText.
+        editText.getLocationOnScreen(origLocation);
+
+        // Tap the EditText to bring up the IME.
+        sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+
+        // Wait until the EditText pops above the IME or until we hit the timeout.
+        editText.getLocationOnScreen(newLocation);
+        long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
+        while (newLocation[1] > rootViewHeight - IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
+            editText.getLocationOnScreen(newLocation);
+            pause(100);
+        }
+
+        assertTrue(newLocation[1] <= rootViewHeight - IME_MIN_HEIGHT);
+
+        // Tell the keyboard to go away.
+        mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
+    }
+
+    public void destructiveCheckImeInitialState(View rootView, View servedView) {
+        if (mExpectAutoPop && (mTargetActivity.getWindow().getAttributes().
+                softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) 
+                == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+            assertTrue(destructiveCheckImeUp(rootView, servedView));
+        } else {
+            assertFalse(destructiveCheckImeUp(rootView, servedView));
+        }
+    }
+    
+    public boolean destructiveCheckImeUp(View rootView, View servedView) {
+        int origHeight;
+        int newHeight;
+        
+        origHeight = rootView.getHeight();
+        
+        // Tell the keyboard to go away.
+        mImm.hideSoftInputFromWindow(servedView.getWindowToken(), 0);
+        
+        // Give it five seconds to adjust
+        newHeight = rootView.getHeight();
+        long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
+        while (Math.abs(newHeight - origHeight) < IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
+            newHeight = rootView.getHeight();
+        }
+        
+        return (Math.abs(origHeight - newHeight) >= IME_MIN_HEIGHT);
+    }
+    
+    void pause(int millis) {
+        try {
+            Thread.sleep(millis);
+        } catch (InterruptedException e) {
+        }
+    }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
new file mode 100755
index 0000000..278efb1
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.app.Activity;
+import android.widget.EditText;
+
+
+public abstract class ManyEditTextActivityBaseTestCase<T extends Activity> extends ImfBaseTestCase<T> {
+  
+    public ManyEditTextActivityBaseTestCase(Class<T> activityClass){
+        super(activityClass);
+    }
+
+    public abstract void testAllEditTextsAdjust();
+
+    public void verifyAllEditTextAdjustment(int numEditTexts, int rootViewHeight) {
+
+        for (int i = 0; i < numEditTexts; i++) {
+            final EditText lastEditText = (EditText) mTargetActivity.findViewById(i);
+            verifyEditTextAdjustment(lastEditText, rootViewHeight);
+        }
+
+    }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
new file mode 100755
index 0000000..4f8d14e
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityNoScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityNoScrollPanScan> {
+
+    public final String TAG = "ManyEditTextActivityNoScrollPanScanTests";
+    
+    public ManyEditTextActivityNoScrollPanScanTests() {
+        super(ManyEditTextActivityNoScrollPanScan.class);
+    }
+
+   
+    @LargeTest
+    public void testAllEditTextsAdjust() {
+        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
+                mTargetActivity.getRootView().getMeasuredHeight());
+    }
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
new file mode 100755
index 0000000..7f98f7f
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollPanScan> {
+
+    public final String TAG = "ManyEditTextActivityScrollPanScanTests";
+    
+    
+    public ManyEditTextActivityScrollPanScanTests() {
+        super(ManyEditTextActivityScrollPanScan.class);
+    }
+    
+    @LargeTest
+    public void testAllEditTextsAdjust() {
+        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
+                mTargetActivity.getRootView().getMeasuredHeight());
+    }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
new file mode 100755
index 0000000..68dae87
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityScrollResizeTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollResize> {
+
+    public final String TAG = "ManyEditTextActivityScrollResizeTests";
+    
+    
+    public ManyEditTextActivityScrollResizeTests() {
+        super(ManyEditTextActivityScrollResize.class);
+    }
+
+    @LargeTest
+    public void testAllEditTextsAdjust() {
+        verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS, 
+                mTargetActivity.getRootView().getMeasuredHeight());
+    }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
new file mode 100755
index 0000000..ed5b0c9
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+
+public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEditTextActivityNotSelected> {
+
+	public final String TAG = "OneEditTextActivityNotSelectedTests";
+	
+    public OneEditTextActivityNotSelectedTests() {
+        super(OneEditTextActivityNotSelected.class);
+    }
+    
+	@LargeTest
+	public void testSoftKeyboardNoAutoPop() {
+	    
+	    // Give the IME 2 seconds to appear.
+	    pause(2000);
+	    
+	    assertFalse(mImm.isAcceptingText());
+	    
+	    View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView();
+        View servedView = ((OneEditTextActivityNotSelected) mTargetActivity).getDefaultFocusedView();
+        
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+        
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+	}
+	
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
new file mode 100755
index 0000000..42fcd66
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 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.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+import android.view.View;
+
+
+public class OneEditTextActivitySelectedTests extends ImfBaseTestCase<OneEditTextActivitySelected> {
+
+    public final String TAG = "OneEditTextActivitySelectedTests";
+    
+    public OneEditTextActivitySelectedTests() {
+        super(OneEditTextActivitySelected.class);
+    }
+    
+    @LargeTest
+    public void testSoftKeyboardAutoPop() {
+        
+        // Give the IME 2 seconds to appear.
+        pause(2000);
+        
+        assertTrue(mImm.isAcceptingText());
+        
+        View rootView = ((OneEditTextActivitySelected) mTargetActivity).getRootView();
+        View servedView = ((OneEditTextActivitySelected) mTargetActivity).getDefaultFocusedView();
+        
+        assertNotNull(rootView);
+        assertNotNull(servedView);
+        
+        destructiveCheckImeInitialState(rootView, servedView);
+        
+        verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+    }
+    
+}
diff --git a/tests/SmokeTest/Android.mk b/tests/SmokeTest/Android.mk
new file mode 100644
index 0000000..0adfd4c
--- /dev/null
+++ b/tests/SmokeTest/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# This builds "SmokeTestApp"
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := SmokeTestApp
+
+include $(BUILD_PACKAGE)
+
+# This builds "SmokeTest"
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/SmokeTest/AndroidManifest.xml b/tests/SmokeTest/AndroidManifest.xml
new file mode 100644
index 0000000..f141bdc
--- /dev/null
+++ b/tests/SmokeTest/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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.smoketest">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:name=".SmokeTestActivity" 
+                  android:label="Smoke Tests">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.TEST" />
+            </intent-filter>
+        </activity>
+
+    </application>
+    
+</manifest>
diff --git a/tests/SmokeTest/README b/tests/SmokeTest/README
new file mode 100644
index 0000000..40218cf
--- /dev/null
+++ b/tests/SmokeTest/README
@@ -0,0 +1,8 @@
+The tests in this folder are a very controlled set of tests that will be run by
+the build system on every single build.  They are intended to run very quickly.
+Please use caution when adding tests here.
+
+If you wish to run these tests, issue the command:
+
+adb shell am instrument \
+  -w com.android.smoketest/.tests.SmokeTestInstrumentationTestRunner
diff --git a/tests/SmokeTest/src/com/android/smoketest/SmokeTestActivity.java b/tests/SmokeTest/src/com/android/smoketest/SmokeTestActivity.java
new file mode 100644
index 0000000..6bc5fd2
--- /dev/null
+++ b/tests/SmokeTest/src/com/android/smoketest/SmokeTestActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest;
+
+import android.app.LauncherActivity;
+import android.content.Intent;
+
+/**
+ * Initial launcher for UI access to smoke tests.  This does not actually launch the tests,
+ * it simply provides manual access to the various UI activities that are used by the tests.
+ * 
+ * To run all of the tests in this suite:
+ * adb shell am instrument \
+ *   -w com.android.smoketest/.tests.SmokeTestInstrumentationTestRunner
+ */
+public class SmokeTestActivity extends LauncherActivity {
+
+    @Override
+    protected Intent getTargetIntent() {
+        // TODO: partition into categories by label like the sample code app
+        Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
+        // TODO: Do we add a new top-level intent?  Or just leave it hardcoded like this?
+        targetIntent.addCategory("android.intent.category.SMOKETEST_INSTRUMENTATION_TEST");
+        targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        return targetIntent;
+    }
+}
diff --git a/tests/SmokeTest/tests/Android.mk b/tests/SmokeTest/tests/Android.mk
new file mode 100644
index 0000000..86bf23d
--- /dev/null
+++ b/tests/SmokeTest/tests/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Notice that we don't have to include the src files of SmokeTestApp because, by
+# running the tests using an instrumentation targeting SmokeTestApp, we
+# automatically get all of its classes loaded into our environment.
+
+LOCAL_PACKAGE_NAME := SmokeTest
+
+LOCAL_INSTRUMENTATION_FOR := SmokeTestApp
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/SmokeTest/tests/AndroidManifest.xml b/tests/SmokeTest/tests/AndroidManifest.xml
new file mode 100644
index 0000000..517eb1e
--- /dev/null
+++ b/tests/SmokeTest/tests/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 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 name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.smoketest.tests">
+
+    <!-- We add an application tag here just so that we can indicate that
+         this package needs to link against the android.test library,
+         which is needed when building test cases. -->    
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--
+    This declares that this app uses the instrumentation test runner targeting
+    the package of com.android.smoketest.  To run the tests use the command:
+    "adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner"
+    -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.smoketest"
+                     android:label="System Smoke Tests"/>
+
+</manifest>
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
new file mode 100644
index 0000000..85b91f1
--- /dev/null
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest;
+
+import com.android.internal.os.RuntimeInit;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.server.data.CrashData;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This smoke test is designed to quickly sniff for any error conditions
+ * encountered after initial startup.
+ */
+public class ProcessErrorsTest extends AndroidTestCase {
+    
+    private final String TAG = "ProcessErrorsTest";
+    
+    protected ActivityManager mActivityManager;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mActivityManager = (ActivityManager) 
+                getContext().getSystemService(Context.ACTIVITY_SERVICE);
+    }
+
+    public void testSetUpConditions() throws Exception {
+        assertNotNull(mActivityManager);
+    }
+
+    public void testNoProcessErrors() throws Exception {
+        List<ActivityManager.ProcessErrorStateInfo> errList;        
+        errList = mActivityManager.getProcessesInErrorState();
+        
+        // note: this contains information about each process that is currently in an error
+        // condition.  if the list is empty (null) then "we're good".  
+        
+        // if the list is non-empty, then it's useful to report the contents of the list
+        // we'll put a copy in the log, and we'll report it back to the framework via the assert.
+        final String reportMsg = reportListContents(errList);
+        if (reportMsg != null) {
+            Log.w(TAG, reportMsg);
+        }
+        
+        // report a non-empty list back to the test framework
+        assertNull(reportMsg, errList);
+    }
+    
+    /**
+     * This helper function will dump the actual error reports.
+     * 
+     * @param errList The error report containing one or more error records.
+     * @return Returns a string containing all of the errors.
+     */
+    private String reportListContents(List<ActivityManager.ProcessErrorStateInfo> errList) {
+        if (errList == null) return null;
+
+        StringBuilder builder = new StringBuilder();
+
+        Iterator<ActivityManager.ProcessErrorStateInfo> iter = errList.iterator();
+        while (iter.hasNext()) {
+            ActivityManager.ProcessErrorStateInfo entry = iter.next();
+
+            String condition;
+            switch (entry.condition) {
+            case ActivityManager.ProcessErrorStateInfo.CRASHED:
+                condition = "CRASHED";
+                break;
+            case ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING:
+                condition = "ANR";
+                break;
+            default:
+                condition = "<unknown>";
+            break;
+            }
+
+            String stackTrace = null;
+            try {
+                if (entry.crashData != null) {
+                    CrashData cd = RuntimeInit.unmarshallException(entry.crashData);
+                    stackTrace = cd.toString();
+                }
+            } catch (RuntimeException e) { }
+            if (stackTrace == null) {
+                stackTrace = "<no stack trace>";
+            }
+
+            final String entryReport = "Process error " + condition + " " + entry.shortMsg +
+                                        " detected in " + entry.processName + " " + entry.tag + 
+                                        ". \n" + stackTrace;
+
+            builder.append(entryReport).append("  ");
+        }
+        return builder.toString();
+    }
+    
+}
diff --git a/tests/SslLoad/Android.mk b/tests/SslLoad/Android.mk
new file mode 100644
index 0000000..f75be8d
--- /dev/null
+++ b/tests/SslLoad/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SslLoad
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SslLoad/AndroidManifest.xml b/tests/SslLoad/AndroidManifest.xml
new file mode 100644
index 0000000..497b1c7
--- /dev/null
+++ b/tests/SslLoad/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.sslload">
+    <uses-permission android:name="android.permission.INTERNET" />
+    <application>
+        <activity android:name="SslLoad" android:label="SSL Load">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest> 
diff --git a/tests/SslLoad/src/com/android/sslload/SslLoad.java b/tests/SslLoad/src/com/android/sslload/SslLoad.java
new file mode 100644
index 0000000..9a08024
--- /dev/null
+++ b/tests/SslLoad/src/com/android/sslload/SslLoad.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008 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.sslload;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Calendar;
+import java.util.Map;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.media.MediaPlayer;
+import android.os.Handler;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+import android.net.http.AndroidHttpClient;
+import android.util.Log;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.HttpResponse;
+
+public class SslLoad extends Activity implements OnClickListener, Runnable {
+
+    private static final String TAG = SslLoad.class.getSimpleName();
+
+    private Button button;
+    private boolean running = false;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        Thread requestThread = new Thread(this);
+        requestThread.setDaemon(true);
+        requestThread.start();
+
+        button = new Button(this);
+        button.setText("GO");
+        button.setOnClickListener(this);
+
+        setContentView(button);
+    }
+    
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        synchronized (this) {
+            running = false;
+        }
+    }
+
+    public void onClick(View v) {
+        synchronized (this) {
+            running = !running;
+            button.setText(running ? "STOP" : "GO");
+            if (running) {
+                this.notifyAll();
+            }
+        }
+    }
+
+    public void run() {
+        boolean error = false;
+        while (true) {
+            synchronized (this) {
+                while (!running) {
+                    try {
+                        this.wait();
+                    } catch (InterruptedException e) { /* ignored */ }
+                }
+            }
+
+            AndroidHttpClient client = AndroidHttpClient.newInstance(
+                    "Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101");
+            try {
+                // Cert. is for "www.google.com", not "google.com".
+                String url = error ? "https://google.com/"
+                        : "https://www.google.com";
+                client.execute(new HttpGet(url),
+                        new ResponseHandler<Void>() {
+                            public Void handleResponse(HttpResponse response) {
+                                /* ignore */
+                                return null;
+                            }
+                        });
+                Log.i(TAG, "Request succeeded.");
+            } catch (IOException e) {
+                Log.w(TAG, "Request failed.", e);
+            }
+
+            client.close();
+            
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) { /* ignored */ }
+
+            error = !error;
+        }
+    }
+}
diff --git a/tests/StatusBar/Android.mk b/tests/StatusBar/Android.mk
new file mode 100644
index 0000000..44f5099
--- /dev/null
+++ b/tests/StatusBar/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := test
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := StatusBarTest
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml
new file mode 100644
index 0000000..9bba79c
--- /dev/null
+++ b/tests/StatusBar/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.statusbartest">
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
+    <uses-permission android:name="android.permission.STATUS_BAR" />
+    <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+    <uses-permission android:name="android.permission.VIBRATE" />
+
+    <application>
+        <activity android:name="StatusBarTest" android:label="_StatusBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="NotificationTestList" android:label="_Notifications">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="ToastTest" android:label="_Toasts">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="PowerTest" android:label="_Power">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/StatusBar/res/drawable/app_gmail.png b/tests/StatusBar/res/drawable/app_gmail.png
new file mode 100644
index 0000000..beaaacf
--- /dev/null
+++ b/tests/StatusBar/res/drawable/app_gmail.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/app_phone.png b/tests/StatusBar/res/drawable/app_phone.png
new file mode 100644
index 0000000..2748c1c
--- /dev/null
+++ b/tests/StatusBar/res/drawable/app_phone.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/ic_statusbar_chat.png b/tests/StatusBar/res/drawable/ic_statusbar_chat.png
new file mode 100644
index 0000000..e08cddb
--- /dev/null
+++ b/tests/StatusBar/res/drawable/ic_statusbar_chat.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/ic_statusbar_email.png b/tests/StatusBar/res/drawable/ic_statusbar_email.png
new file mode 100644
index 0000000..19c9005
--- /dev/null
+++ b/tests/StatusBar/res/drawable/ic_statusbar_email.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/ic_statusbar_missedcall.png b/tests/StatusBar/res/drawable/ic_statusbar_missedcall.png
new file mode 100644
index 0000000..ced62d7
--- /dev/null
+++ b/tests/StatusBar/res/drawable/ic_statusbar_missedcall.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/icon1.png b/tests/StatusBar/res/drawable/icon1.png
new file mode 100644
index 0000000..abfb6fa
--- /dev/null
+++ b/tests/StatusBar/res/drawable/icon1.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/icon2.png b/tests/StatusBar/res/drawable/icon2.png
new file mode 100644
index 0000000..564b38b
--- /dev/null
+++ b/tests/StatusBar/res/drawable/icon2.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/icon3.png b/tests/StatusBar/res/drawable/icon3.png
new file mode 100644
index 0000000..e765d8f
--- /dev/null
+++ b/tests/StatusBar/res/drawable/icon3.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/icon4.png b/tests/StatusBar/res/drawable/icon4.png
new file mode 100644
index 0000000..5f33885
--- /dev/null
+++ b/tests/StatusBar/res/drawable/icon4.png
Binary files differ
diff --git a/tests/StatusBar/res/layout/chrono_notification.xml b/tests/StatusBar/res/layout/chrono_notification.xml
new file mode 100644
index 0000000..913a860
--- /dev/null
+++ b/tests/StatusBar/res/layout/chrono_notification.xml
@@ -0,0 +1,41 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="80sp"
+    android:orientation="horizontal"
+    >
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:layout_weight="0"
+        android:orientation="vertical"
+        >
+
+        <ImageView android:id="@+id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="45dp"
+            android:layout_gravity="center"
+            android:scaleType="fitCenter"
+            android:src="@android:drawable/sym_def_app_icon"
+            />
+
+        <Chronometer android:id="@+id/time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textColor="#ffffffff" />
+
+    </LinearLayout>
+
+    <TextView android:id="@+id/appName"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_weight="1"
+        android:paddingTop="4dp"
+        android:textSize="12sp"
+        android:textColor="#ffffffff"
+        />
+
+</LinearLayout>
+
diff --git a/tests/StatusBar/res/raw/ringer.mp3 b/tests/StatusBar/res/raw/ringer.mp3
new file mode 100644
index 0000000..aa052e7
--- /dev/null
+++ b/tests/StatusBar/res/raw/ringer.mp3
Binary files differ
diff --git a/tests/StatusBar/res/values/strings.xml b/tests/StatusBar/res/values/strings.xml
new file mode 100644
index 0000000..0c2cf0d
--- /dev/null
+++ b/tests/StatusBar/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="mainLabel">Hello <u>th<ignore>e</ignore>re</u>, <i>you</i> <b>Activity</b>!</string>
+    <string name="back">Back</string>
+    <string name="clear">Clear</string>
+</resources>
+
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
new file mode 100644
index 0000000..e1a0e7d
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2007 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.statusbartest;
+
+import android.app.ListActivity;
+import android.app.PendingIntent;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.ListView;
+import android.content.Intent;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+import android.os.PowerManager;
+
+public class NotificationTestList extends TestActivity
+{
+    private final static String TAG = "NotificationTestList";
+
+    NotificationManager mNM;
+    Vibrator mVibrator = new Vibrator();
+    Handler mHandler = new Handler();
+
+    long mChronometerBase = 0;
+
+    @Override
+    protected String tag() {
+        return TAG;
+    }
+
+    @Override
+    protected Test[] tests() {
+        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
+        
+        return mTests;
+    }
+
+    private Test[] mTests = new Test[] {
+        new Test("Crash") {
+            public void run()
+            {
+                PowerManager.WakeLock wl
+                        = ((PowerManager)NotificationTestList.this.getSystemService("power"))
+                            .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "crasher");
+                wl.acquire();
+                mHandler.postDelayed(new Runnable() {
+                            public void run() {
+                                throw new RuntimeException("Die!");
+                            }
+                        }, 10000);
+
+            }
+        },
+
+        new Test("No view") {
+            public void run() {
+                Notification n = new Notification(R.drawable.icon1, "No view",
+                        System.currentTimeMillis());
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("No intent") {
+            public void run() {
+                Notification n = new Notification(R.drawable.icon1, "No intent",
+                        System.currentTimeMillis());
+                n.setLatestEventInfo(NotificationTestList.this, "No intent",
+                            "No intent", null);
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("Layout") {
+            public void run()
+            {
+
+                mNM.notify(1, new Notification(NotificationTestList.this,
+                            R.drawable.ic_statusbar_missedcall,
+                            null, System.currentTimeMillis()-(1000*60*60*24),
+                            "(453) 123-2328",
+                            "", null));
+
+                mNM.notify(2, new Notification(NotificationTestList.this,
+                            R.drawable.ic_statusbar_email,
+                            null, System.currentTimeMillis(),
+                            "Mark Willem, Me (2)",
+                            "Re: Didn't you get the memo?", null));
+
+                mNM.notify(3, new Notification(NotificationTestList.this,
+                            R.drawable.ic_statusbar_chat,
+                            null, System.currentTimeMillis()+(1000*60*60*24),
+                            "Sophia Winterlanden",
+                            "Lorem ipsum dolor sit amet.", null));
+            }
+        },
+
+        new StateStress("Stress - Ongoing / Latest", 100, 100, new Runnable[] {
+                new Runnable() {
+                    public void run() {
+                        Log.d(TAG, "Stress - Ongoing/Latest 0");
+                        Notification n = new Notification(NotificationTestList.this,
+                                R.drawable.icon3,
+                                null, System.currentTimeMillis(), "Stress - Ongoing",
+                                "Notify me!!!", null);
+                        n.flags |= Notification.FLAG_ONGOING_EVENT;
+                        mNM.notify(1, n);
+                    }
+                },
+                new Runnable() {
+                    public void run() {
+                        Log.d(TAG, "Stress - Ongoing/Latest 1");
+                        Notification n = new Notification(NotificationTestList.this,
+                                R.drawable.icon4,
+                                null, System.currentTimeMillis(), "Stress - Latest",
+                                "Notify me!!!", null);
+                        n.flags |= Notification.FLAG_ONGOING_EVENT;
+                        mNM.notify(1, n);
+                    }
+                }
+            }),
+
+        new Test("Long") {
+            public void run()
+            {
+                Notification n = new Notification();
+                n.defaults |= Notification.DEFAULT_SOUND ;
+                n.vibrate = new long[] {
+                        300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+                        300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 
+                        300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("Default All") {
+            public void run()
+            {
+                Notification n = new Notification();
+                n.defaults |= Notification.DEFAULT_ALL;
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("Default All, once") {
+            public void run()
+            {
+                Notification n = new Notification();
+                n.defaults |= Notification.DEFAULT_ALL;
+                n.flags |= Notification.FLAG_ONLY_ALERT_ONCE ;
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("Content Sound") {
+            public void run()
+            {
+                Notification n = new Notification();
+                n.sound = Uri.parse(
+                        "content://media/internal/audio/media/7");
+
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("Resource Sound") {
+            public void run()
+            {
+                Notification n = new Notification();
+                n.sound = Uri.parse(
+                        "android.resource://com.android.notificationtest/raw/ringer");
+                Log.d(TAG, "n.sound=" + n.sound);
+
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("Sound and Cancel") {
+            public void run()
+            {
+                Notification n = new Notification();
+                n.sound = Uri.parse(
+                            "content://media/internal/audio/media/7");
+
+                mNM.notify(1, n);
+                SystemClock.sleep(200);
+                mNM.cancel(1);
+            }
+        },
+
+        new Test("Vibrate") {
+            public void run()
+            {
+                Notification n = new Notification();
+                    n.vibrate = new long[] { 0, 700, 500, 1000 };
+
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("Vibrate and cancel") {
+            public void run()
+            {
+                Notification n = new Notification();
+                    n.vibrate = new long[] { 0, 700, 500, 1000 };
+
+                mNM.notify(1, n);
+                SystemClock.sleep(500);
+                mNM.cancel(1);
+            }
+        },
+
+        new Test("Vibrate pattern") {
+            public void run()
+            {
+                mVibrator.vibrate(new long[] { 250, 1000, 500, 2000 }, -1);
+            }
+        },
+
+        new Test("Vibrate pattern repeating") {
+            public void run()
+            {
+                mVibrator.vibrate(new long[] { 250, 1000, 500 }, 1);
+            }
+        },
+
+        new Test("Vibrate 3s") {
+            public void run()
+            {
+                mVibrator.vibrate(3000);
+            }
+        },
+
+        new Test("Vibrate 100s") {
+            public void run()
+            {
+                mVibrator.vibrate(100000);
+            }
+        },
+
+        new Test("Vibrate off") {
+            public void run()
+            {
+                mVibrator.cancel();
+            }
+        },
+
+        new Test("Cancel #1") {
+            public void run() {
+                mNM.cancel(1);
+            }
+        },
+
+        new Test("Cancel #1 in 3 sec") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                            public void run() {
+                                Log.d(TAG, "Cancelling now...");
+                                mNM.cancel(1);
+                            }
+                        }, 3000);
+            }
+        },
+
+        new Test("Cancel #2") {
+            public void run() {
+                mNM.cancel(2);
+            }
+        },
+
+        new Test("Persistent #1") {
+            public void run() {
+                Notification n = new Notification(R.drawable.icon1, "tick tick tick",
+                        System.currentTimeMillis());
+                n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
+                            "This is a notification!!!", makeIntent());
+                mNM.notify(1, n);
+            }
+        },
+
+        new Test("Persistent #1 in 3 sec") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                            public void run() {
+                                Notification n = new Notification(R.drawable.icon1,
+                                        "            "
+                                        + "tick tock tick tock\n\nSometimes notifications can "
+                                        + "be really long and wrap to more than one line.\n"
+                                        + "Sometimes."
+                                        + "Ohandwhathappensifwehaveonereallylongstringarewesure"
+                                        + "thatwesegmentitcorrectly?\n",
+                                        System.currentTimeMillis());
+                                n.setLatestEventInfo(NotificationTestList.this,
+                                        "Still Persistent #1",
+                                        "This is still a notification!!!",
+                                        makeIntent());
+                                mNM.notify(1, n);
+                            }
+                        }, 3000);
+            }
+        },
+
+        new Test("Persistent #2") {
+            public void run() {
+                Notification n = new Notification(R.drawable.icon2, "tock tock tock",
+                        System.currentTimeMillis());
+                n.setLatestEventInfo(NotificationTestList.this, "Persistent #2",
+                            "Notify me!!!", makeIntent());
+                mNM.notify(2, n);
+            }
+        },
+
+        new Test("Persistent #2 Vibrate") {
+            public void run() {
+                Notification n = new Notification(R.drawable.icon2, "tock tock tock",
+                        System.currentTimeMillis());
+                n.setLatestEventInfo(NotificationTestList.this, "Persistent #2",
+                            "Notify me!!!", makeIntent());
+                n.defaults = Notification.DEFAULT_VIBRATE;
+                mNM.notify(2, n);
+            }
+        },
+
+        new Test("Chronometer Start") {
+            public void run() {
+                Notification n = new Notification(R.drawable.icon2, "me me me me",
+                                                    System.currentTimeMillis());
+                n.contentView = new RemoteViews(getPackageName(), R.layout.chrono_notification);
+                mChronometerBase = SystemClock.elapsedRealtime();
+                n.contentView.setChronometer(R.id.time, mChronometerBase, "Yay! (%s)", true);
+                n.flags |= Notification.FLAG_ONGOING_EVENT;
+                n.contentIntent = makeIntent();
+                mNM.notify(2, n);
+            }
+        },
+
+        new Test("Chronometer Stop") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            Log.d(TAG, "Chronometer Stop");
+                            Notification n = new Notification();
+                            n.icon = R.drawable.icon1;
+                            n.contentView = new RemoteViews(getPackageName(),
+                                                             R.layout.chrono_notification);
+                            n.contentView.setChronometer(R.id.time, mChronometerBase, null, false);
+                            n.contentIntent = makeIntent();
+                            mNM.notify(2, n);
+                        }
+                    }, 3000);
+            }
+        },
+
+        new Test("Sequential Persistent") {
+            public void run() {
+                mNM.notify(1, notificationWithNumbers(1));
+                mNM.notify(2, notificationWithNumbers(2));
+            }
+        },
+
+        new Test("Replace Persistent") {
+            public void run() {
+                mNM.notify(1, notificationWithNumbers(1));
+                mNM.notify(1, notificationWithNumbers(1));
+            }
+        },
+
+        new Test("Run and Cancel (n=1)") {
+            public void run() {
+                mNM.notify(1, notificationWithNumbers(1));
+                mNM.cancel(1);
+            }
+        },
+
+        new Test("Run an Cancel (n=2)") {
+            public void run() {
+                mNM.notify(1, notificationWithNumbers(1));
+                mNM.notify(2, notificationWithNumbers(2));
+                mNM.cancel(2);
+            }
+        },
+
+        // Repeatedly notify and cancel -- triggers bug #670627
+        new Test("Bug 670627") {
+            public void run() {
+                for (int i = 0; i < 10; i++) {
+                  Log.d(TAG, "Add two notifications");
+                  mNM.notify(1, notificationWithNumbers(1));
+                  mNM.notify(2, notificationWithNumbers(2));
+                  Log.d(TAG, "Cancel two notifications");
+                  mNM.cancel(1);
+                  mNM.cancel(2);
+                }
+            }
+        },
+
+        new Test("Ten Notifications") {
+            public void run() {
+                for (int i = 0; i < 2; i++) {
+                    Notification n = new Notification(NotificationTestList.this, R.drawable.icon2,
+                            null, System.currentTimeMillis(), "Persistent #" + i,
+                            "Notify me!!!" + i, null);
+                    n.flags |= Notification.FLAG_ONGOING_EVENT;
+                    n.number = i;
+                    mNM.notify((i+1)*10, n);
+                }
+                for (int i = 2; i < 10; i++) {
+                    Notification n = new Notification(NotificationTestList.this, R.drawable.icon2,
+                            null, System.currentTimeMillis(), "Persistent #" + i,
+                            "Notify me!!!" + i, null);
+                    n.number = i;
+                    mNM.notify((i+1)*10, n);
+                }
+            }
+        },
+        
+        new Test("Cancel eight notifications") {
+            public void run() {
+                for (int i = 1; i < 9; i++) {
+                    mNM.cancel((i+1)*10);
+                }
+            }
+        },
+        
+        new Test("Persistent with numbers 1") {
+            public void run() {
+                mNM.notify(1, notificationWithNumbers(1));
+            }
+        },
+
+        new Test("Persistent with numbers 222") {
+            public void run() {
+                mNM.notify(1, notificationWithNumbers(22));
+            }
+        },
+
+        new Test("Persistent with numbers 333") {
+            public void run() {
+                mNM.notify(1, notificationWithNumbers(333));
+            }
+        },
+
+        new Test("Persistent with numbers 4444") {
+            public void run() {
+                mNM.notify(1, notificationWithNumbers(4444));
+            }
+        },
+
+    };
+
+    private Notification notificationWithNumbers(int num) {
+        Notification n = new Notification(this, R.drawable.icon2, null, System.currentTimeMillis(),
+                "Persistent #2", "Notify me!!!", null);
+        n.number = num;
+        return n;
+    }
+
+    private PendingIntent makeIntent() {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setComponent(new android.content.ComponentName(
+                    "com.android.contacts",
+                    "com.android.contacts.ContactsActivity"));
+        return PendingIntent.getActivity(this, 0, intent, 0);
+    }
+
+    class StateStress extends Test {
+        StateStress(String name, int pause, int iterations, Runnable[] tasks) {
+            super(name);
+            mPause = pause;
+            mTasks = tasks;
+            mIteration = iterations;
+        }
+        Runnable[] mTasks;
+        int mNext;
+        int mIteration;
+        long mPause;
+        Runnable mRunnable = new Runnable() {
+            public void run() {
+                mTasks[mNext].run();
+                mNext++;
+                if (mNext >= mTasks.length) {
+                    mNext = 0;
+                    mIteration--;
+                    if (mIteration <= 0) {
+                        return;
+                    }
+                }
+                mHandler.postDelayed(mRunnable, mPause);
+            }
+        };
+        public void run() {
+            mNext = 0;
+            mHandler.postDelayed(mRunnable, mPause);
+        }
+    }
+}
+
diff --git a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
new file mode 100644
index 0000000..f236a4b
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008 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.statusbartest;
+
+import android.app.ListActivity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.widget.ListView;
+import android.content.Intent;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.StatusBarManager;
+import android.os.RemoteException;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.LocalPowerManager;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+import android.os.PowerManager;
+
+public class PowerTest extends TestActivity
+{
+    private final static String TAG = "PowerTest";
+    IPowerManager mPowerManager;
+    int mPokeState = 0;
+    IBinder mPokeToken = new Binder();
+    Handler mHandler = new Handler();
+
+    @Override
+    protected String tag() {
+        return TAG;
+    }
+
+    @Override
+    protected Test[] tests() {
+        mPowerManager = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
+        
+        return mTests;
+    }
+    private Test[] mTests = new Test[] {
+        new Test("Touch events don't poke") {
+            public void run() {
+                mPokeState |= LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS;
+                try {
+                    mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        },
+        new Test("Touch events poke") {
+            public void run() {
+                mPokeState &= ~LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS;
+                try {
+                    mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        },
+        new Test("Short timeout") {
+            public void run() {
+                mPokeState &= ~LocalPowerManager.POKE_LOCK_TIMEOUT_MASK;
+                mPokeState |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT;
+                try {
+                    mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        },
+        new Test("Medium timeout") {
+            public void run() {
+                mPokeState &= ~LocalPowerManager.POKE_LOCK_TIMEOUT_MASK;
+                mPokeState |= LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT;
+                try {
+                    mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        },
+        new Test("Normal timeout") {
+            public void run() {
+                mPokeState &= ~LocalPowerManager.POKE_LOCK_TIMEOUT_MASK;
+                try {
+                    mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        },
+        new Test("Illegal timeout") {
+            public void run() {
+                mPokeState |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT
+                        | LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT;
+                try {
+                    mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        },
+    };
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
new file mode 100644
index 0000000..275e5cb6
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 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.statusbartest;
+
+import android.app.ListActivity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.ListView;
+import android.content.Intent;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.StatusBarManager;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+import android.os.PowerManager;
+
+public class StatusBarTest extends TestActivity
+{
+    private final static String TAG = "StatusBarTest";
+    StatusBarManager mStatusBarManager;
+    NotificationManager mNotificationManager;
+    Handler mHandler = new Handler();
+
+    @Override
+    protected String tag() {
+        return TAG;
+    }
+
+    @Override
+    protected Test[] tests() {
+        mStatusBarManager = (StatusBarManager)getSystemService(STATUS_BAR_SERVICE);
+        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+        
+        return mTests;
+    }
+
+    private Test[] mTests = new Test[] {
+        new Test("Disable Alerts") {
+            public void run() {
+                mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ALERTS);
+            }
+        },
+        new Test("Disable Expand in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Disable Notifications in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS);
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Disable Both in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND
+                                    | StatusBarManager.DISABLE_NOTIFICATION_ICONS);
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Disable None in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.disable(0);
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Notify in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mNotificationManager.notify(1,
+                                    new Notification(StatusBarTest.this,
+                                            R.drawable.ic_statusbar_missedcall,
+                                            "tick tick tick",
+                                            System.currentTimeMillis()-(1000*60*60*24),
+                                            "(453) 123-2328",
+                                            "", null
+                                            ));
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Cancel Notification in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mNotificationManager.cancel(1);
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Expand in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.expand();
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Expand in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.expand();
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Collapse in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.collapse();
+                        }
+                    }, 3000);
+            }
+        },
+        new Test("Toggle in 3 sec.") {
+            public void run() {
+                mHandler.postDelayed(new Runnable() {
+                        public void run() {
+                            mStatusBarManager.toggle();
+                        }
+                    }, 3000);
+            }
+        },
+    };
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/TestActivity.java b/tests/StatusBar/src/com/android/statusbartest/TestActivity.java
new file mode 100644
index 0000000..6a8c62e
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/TestActivity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 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.statusbartest;
+
+import android.app.ListActivity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.ListView;
+import android.content.Intent;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+import android.os.PowerManager;
+
+public abstract class TestActivity extends ListActivity
+{
+    Test[] mTests;
+
+    protected abstract String tag();
+    protected abstract Test[] tests();
+
+    abstract class Test {
+        String name;
+        Test(String n) {
+            name = n;
+        }
+        abstract void run();
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mTests = tests();
+
+        String[] labels = new String[mTests.length];
+        for (int i=0; i<mTests.length; i++) {
+            labels[i] = mTests[i].name;
+        }
+
+        setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, labels));
+    }
+
+    @Override
+    public void onListItemClick(ListView l, View v, int position, long id)
+    {
+        Test t = mTests[position];
+        Log.d(tag(), "Test: " + t.name);
+        t.run();
+    }
+    
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/ToastTest.java b/tests/StatusBar/src/com/android/statusbartest/ToastTest.java
new file mode 100644
index 0000000..018c9f2
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/ToastTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 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.statusbartest;
+
+import android.app.ListActivity;
+import android.app.PendingIntent;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.ListView;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.view.Gravity;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+import android.widget.TextView;
+import android.os.PowerManager;
+
+public class ToastTest extends TestActivity
+{
+    private final static String TAG = "ToastTest";
+
+    Handler mHandler = new Handler();
+    Toast mToast1;
+    Toast mToast2;
+
+    @Override
+    protected String tag() {
+        return TAG;
+    }
+
+    @Override
+    protected Test[] tests() {
+        return mTests;
+    }
+
+    private Test[] mTests = new Test[] {
+        new Test("Make Toast #1") {
+            public void run()
+            {
+                mToast1 = Toast.makeText(ToastTest.this, "hi 1", Toast.LENGTH_SHORT);
+            }
+        },
+
+        new Test("Show Toast #1") {
+            public void run()
+            {
+                mToast1.show();
+            }
+        },
+
+        new Test("Update Toast #1") {
+            public void run()
+            {
+                TextView view = new TextView(ToastTest.this);
+                view.setText("replaced!");
+                mToast1.setView(view);
+                mToast1.show();
+            }
+        },
+
+        new Test("Make Toast #2") {
+            public void run()
+            {
+                mToast2 = Toast.makeText(ToastTest.this, "hi 2", Toast.LENGTH_SHORT);
+            }
+        },
+
+        new Test("Show Toast #2") {
+            public void run()
+            {
+                mToast2.show();
+            }
+        },
+
+        new Test("Gravity Toast LEFT") {
+            public void run()
+            {
+                Toast toast = Toast.makeText(ToastTest.this, "LEFT", Toast.LENGTH_SHORT);
+                toast.setGravity(Gravity.LEFT, 0, 0);
+                toast.show();
+            }
+        },
+
+        new Test("Gravity Toast FILL_HORIZONTAL") {
+            public void run()
+            {
+                Toast toast = Toast.makeText(ToastTest.this, "FILL_HORIZONTAL",
+                        Toast.LENGTH_SHORT);
+                toast.setGravity(Gravity.FILL_HORIZONTAL, 0, 0);
+                toast.show();
+            }
+        },
+
+    };
+}
+
diff --git a/tests/framework-tests/Android.mk b/tests/framework-tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/tests/framework-tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/tests/framework-tests/README b/tests/framework-tests/README
new file mode 100644
index 0000000..7b46b25
--- /dev/null
+++ b/tests/framework-tests/README
@@ -0,0 +1,5 @@
+This package contains tests which need to access package-private members in the framework code.
+To do this, the tests must be loaded in the same class loader as the classes which they are
+testing. This package is loaded in the boot classpath.
+
+Run these tests via AndroidTests -> FrameworkTests.
diff --git a/tests/framework-tests/src/Android.mk b/tests/framework-tests/src/Android.mk
new file mode 100644
index 0000000..54e33a4
--- /dev/null
+++ b/tests/framework-tests/src/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE := framework-tests
+
+LOCAL_JAVA_LIBRARIES := android.policy_phone android.test.runner
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/tests/framework-tests/src/android/test/FrameworkTests.java b/tests/framework-tests/src/android/test/FrameworkTests.java
new file mode 100644
index 0000000..b5f6292
--- /dev/null
+++ b/tests/framework-tests/src/android/test/FrameworkTests.java
@@ -0,0 +1,28 @@
+package android.test;
+
+import com.android.internal.os.LoggingPrintStreamTest;
+import android.util.EventLogFunctionalTest;
+import android.util.EventLogTest;
+import junit.framework.TestSuite;
+import com.android.internal.http.multipart.MultipartTest;
+import com.android.internal.policy.impl.LockPatternKeyguardViewTest;
+
+/**
+ * Tests that are loaded in the boot classpath along with the Android framework
+ * classes. This enables you to access package-private members in the framework
+ * classes; doing so is not possible when the test classes are loaded in an
+ * application classloader.
+ */
+public class FrameworkTests {
+    public static TestSuite suite() {
+        TestSuite suite = new TestSuite(FrameworkTests.class.getName());
+
+        suite.addTestSuite(MultipartTest.class);
+        suite.addTestSuite(EventLogTest.class);
+        suite.addTestSuite(EventLogFunctionalTest.class);
+        suite.addTestSuite(LoggingPrintStreamTest.class);
+        suite.addTestSuite(LockPatternKeyguardViewTest.class);
+
+        return suite;
+    }
+}
diff --git a/tests/framework-tests/src/android/text/PackedIntVectorTest.java b/tests/framework-tests/src/android/text/PackedIntVectorTest.java
new file mode 100644
index 0000000..78cdee9
--- /dev/null
+++ b/tests/framework-tests/src/android/text/PackedIntVectorTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2007 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;
+
+import android.text.PackedIntVector;
+import junit.framework.TestCase;
+
+/**
+ * PackedIntVectorTest tests the features of android.util.PackedIntVector.
+ */
+public class PackedIntVectorTest extends TestCase {
+ 
+    public void testBasic() throws Exception {
+        for (int width = 0; width < 10; width++) {
+            PackedIntVector p = new PackedIntVector(width);
+            int[] ins = new int[width];
+
+            for (int height = width * 2; height < width * 4; height++) {
+                assertEquals(p.width(), width);
+
+                // Test adding rows.
+
+                for (int i = 0; i < height; i++) {
+                    int at;
+
+                    if (i % 2 == 0) {
+                        at = i;
+                    } else {
+                        at = p.size() - i;
+                    }
+
+                    for (int j = 0; j < width; j++) {
+                        ins[j] = i + j;
+                    }
+
+                    if (i == height / 2) {
+                        p.insertAt(at, null);
+                    } else {
+                        p.insertAt(at, ins);
+                    }
+
+                    assertEquals(p.size(), i + 1);
+
+                    for (int j = 0; j < width; j++) {
+                        if (i == height / 2) {
+                            assertEquals(0, p.getValue(at, j));
+                        } else {
+                            assertEquals(p.getValue(at, j), i + j);
+                        }
+                    }
+                }
+
+                // Test setting values.
+
+                for (int i = 0; i < height; i++) {
+                    for (int j = 0; j < width; j++) {
+                        p.setValue(i, j, i * j);
+
+                        assertEquals(p.getValue(i, j), i * j);
+                    }
+                }
+
+                // Test offsetting values.
+
+                for (int j = 0; j < width; j++) {
+                    p.adjustValuesBelow(j * 2, j, j + 27);
+                }
+
+                for (int i = 0; i < height; i++) {
+                    for (int j = 0; j < width; j++) {
+                        int expect = i * j;
+
+                        if (i >= j * 2) {
+                            expect += j + 27;
+                        }
+
+                        assertEquals(p.getValue(i, j), expect);
+                    }
+                }
+
+                for (int j = 0; j < width; j++) {
+                    p.adjustValuesBelow(j, j, j * j + 14);
+                }
+
+                for (int i = 0; i < height; i++) {
+                    for (int j = 0; j < width; j++) {
+                        int expect = i * j;
+
+                        if (i >= j * 2) {
+                            expect += j + 27;
+                        }
+                        if (i >= j) {
+                            expect += j * j + 14;
+                        }
+
+                        assertEquals(p.getValue(i, j), expect);
+                    }
+                }
+
+                // Test undoing offsets.
+
+                for (int j = 0; j < width; j++) {
+                    p.adjustValuesBelow(j * 2, j, -(j + 27));
+                    p.adjustValuesBelow(j, j, -(j * j + 14));
+                }
+
+                for (int i = 0; i < height; i++) {
+                    for (int j = 0; j < width; j++) {
+                        assertEquals(p.getValue(i, j), i * j);
+                    }
+                }
+
+                // Test deleting rows.
+
+                while (p.size() > 0) {
+                    int osize = p.size();
+                    int del = osize / 3;
+
+                    if (del == 0) {
+                        del = 1;
+                    }
+
+                    int at = (osize - del) / 2;
+                    p.deleteAt(at, del);
+
+                    assertEquals(p.size(), osize - del);
+
+                    for (int i = 0; i < at; i++) {
+                        for (int j = 0; j < width; j++) {
+                            assertEquals(p.getValue(i, j), i * j);
+                        }
+                    }
+
+                    for (int i = at; i < p.size(); i++) {
+                        for (int j = 0; j < width; j++) {
+                            assertEquals(p.getValue(i, j), (i + height - p.size()) * j);
+                        }
+                    }
+                }
+
+                assertEquals(0, p.size());
+            }
+        }
+    }
+}
diff --git a/tests/framework-tests/src/android/util/EventLogFunctionalTest.java b/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
new file mode 100644
index 0000000..8263083
--- /dev/null
+++ b/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007 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.util;
+
+import android.os.Process;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.TestCase;
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+
+/**
+ * Functional tests of EventLog.
+ */
+
+public class EventLogFunctionalTest extends TestCase {
+    private static final String TAG = "EventLogFunctionalTest";
+
+    private static final int TAG_SIZE = 4;
+    private static final int TYPE_FIELD_SIZE = 1;
+    private static final int STARTING_POS_OF_PAYLOAD = TAG_SIZE + TYPE_FIELD_SIZE;
+
+    private static final int TEST_TAG = 42;
+    private static final int TEST_TAG2 = 314;
+
+    //todo:  For now all we do is test the returned length.  More to come.
+    public void testLogOfPosInt() throws Exception {
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, 0x01020304);
+        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 4, numBytes);
+    }
+
+    //todo:  For now all we do is test the returned length.  More to come.
+    public void testLogOfPosLong() throws Exception {
+        final int numBytes =  EventLog.writeEvent(TEST_TAG2, 0x0102030405060708L);
+        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 8, numBytes);
+    }
+
+    //todo:  For now all we do is test the returned length.  More to come.
+    public void testLogOfString() throws Exception {
+        final String valueStr = "foo bar baz";
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, valueStr);
+        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 4 + valueStr.length() + 1, numBytes);
+     }
+
+    public void testLogOfListWithOneInt() throws Exception {
+        final EventLog.List list = new EventLog.List(1234);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + 1 + 4 + 1, numBytes);
+    }
+
+    public void testLogOfListWithMultipleInts() throws Exception {
+       final EventLog.List list = new EventLog.List(1234, 2345, 3456);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + 1 + 4 + 1 + 4 + 1 + 4 + 1, numBytes);
+    }
+
+    public void testLogOfListWithEmbeddedList() throws Exception {
+        final EventLog.List list = new EventLog.List(
+                new EventLog.List(1234, 2345, 3456));
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 2 + 1 + 1 + 4 + 1 + 4 + 1 + 4 + 1, numBytes);
+    }
+
+    public void testEventLargerThanInitialBufferCapacity() throws Exception {
+        final Integer[] array = new Integer[127];
+        for (int i = 0; i < array.length; i++) {
+            array[i] = i;
+        }
+        final EventLog.List list = new EventLog.List((Object[]) array);
+        final int numBytes =  EventLog.writeEvent(TEST_TAG, list);
+        Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + (5 * array.length) + 1, numBytes);
+    }
+
+    // This test is obsolete. See http://b/issue?id=1262082
+    public void disableTestReadSimpleEvent() throws Exception {
+        long when = System.currentTimeMillis();
+        EventLog.writeEvent(2718, 12345);
+        Log.i(TAG, "Wrote simple event at T=" + when);
+
+        ArrayList<EventLog.Event> list = new ArrayList<EventLog.Event>();
+        EventLog.readEvents(new int[] { 2718 }, list);
+
+        boolean found = false;
+        for (EventLog.Event event : list) {
+            assertEquals(event.getTag(), 2718);
+            long eventTime = event.getTimeNanos() / 1000000;
+            Log.i(TAG, "  Found event T=" + eventTime);
+            if (eventTime > when - 100 && eventTime < when + 1000) {
+                assertEquals(event.getProcessId(), Process.myPid());
+                assertEquals(event.getThreadId(), Process.myTid());
+                assertEquals(event.getData(), 12345);
+
+                assertFalse(found);
+                found = true;
+            }
+        }
+
+        assertTrue(found);
+    }
+
+    // This test is obsolete. See http://b/issue?id=1262082
+    public void disableTestReadCompoundEntry() throws Exception {
+        long when = System.currentTimeMillis();
+        EventLog.writeEvent(2719,
+                new EventLog.List(1l, new EventLog.List("2", "three", "4"), 5));
+        Log.i(TAG, "Wrote compound event at T=" + when);
+
+        ArrayList<EventLog.Event> list = new ArrayList<EventLog.Event>();
+        EventLog.readEvents(new int[] { 2719 }, list);
+
+        boolean found = false;
+        for (EventLog.Event event : list) {
+            long eventTime = event.getTimeNanos() / 1000000;
+            Log.i(TAG, "  Found event T=" + eventTime);
+            if (eventTime > when - 100 && eventTime < when + 1000) {
+                EventLog.List data = (EventLog.List) event.getData();
+                assertEquals(data.getNumItems(), 3);
+
+                EventLog.List nested = (EventLog.List) data.getItem(1);
+                assertEquals(nested.getNumItems(), 3);
+
+                assertEquals(data.getItem(0), 1l);
+                assertEquals(nested.getItem(0), "2");
+                assertEquals(nested.getItem(1), "three");
+                assertEquals(nested.getItem(2), "4");
+                assertEquals(data.getItem(2), 5);
+
+                assertFalse(found);
+                found = true;
+            }
+        }
+
+        assertTrue(found);
+    }
+
+    public void testEventLogTagsFile() throws Exception {
+        EventLogTags tags = new EventLogTags();
+        assertEquals(tags.get("answer").mTag, 42);
+        assertEquals(tags.get("pi").mTag, 314);
+        assertEquals(tags.get("e").mTag, 2718);
+        assertEquals(tags.get(42).mName, "answer");
+        assertEquals(tags.get(314).mName, "pi");
+        assertEquals(tags.get(2718).mName, "e");
+    }
+}
diff --git a/tests/framework-tests/src/android/util/EventLogTest.java b/tests/framework-tests/src/android/util/EventLogTest.java
new file mode 100644
index 0000000..4a5d888
--- /dev/null
+++ b/tests/framework-tests/src/android/util/EventLogTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 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.util;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * tests for {@link EventLog}
+ */
+
+public class EventLogTest extends TestCase {
+    private static final int TEST_TAG = 42;
+
+    public void testIllegalListTypesThrowException() throws Exception {
+        try {
+            EventLog.writeEvent(TEST_TAG, new EventLog.List(new Object()));
+            fail("Can't create List with any old Object");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            EventLog.writeEvent(TEST_TAG, new EventLog.List((byte) 1));
+            fail("Can't create List with any old byte");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
+
+    void assertIntInByteArrayEquals(int expected, byte[] buf, int pos) {
+        ByteBuffer computedBuf = ByteBuffer.wrap(buf).order(ByteOrder.nativeOrder());
+        int computed = computedBuf.getInt(pos);
+        Assert.assertEquals(expected, computed);
+    }
+
+    void assertLongInByteArrayEquals(long expected, byte[] buf, int pos) {
+        ByteBuffer computedBuf = ByteBuffer.wrap(buf).order(ByteOrder.nativeOrder());
+        long computed = computedBuf.getLong(pos);
+        Assert.assertEquals(expected, computed);
+    }
+
+    void assertStringInByteArrayEquals(String expected, byte[] buf, int pos) {
+        byte[] expectedBytes = expected.getBytes();
+        Assert.assertTrue(expectedBytes.length <= buf.length - pos);
+        for (byte expectedByte : expectedBytes) {
+            Assert.assertEquals(expectedByte, buf[pos++]);
+        }
+    }
+}
diff --git a/tests/framework-tests/src/com/android/internal/http/multipart/MultipartTest.java b/tests/framework-tests/src/com/android/internal/http/multipart/MultipartTest.java
new file mode 100644
index 0000000..8b48ed0
--- /dev/null
+++ b/tests/framework-tests/src/com/android/internal/http/multipart/MultipartTest.java
@@ -0,0 +1,102 @@
+package com.android.internal.http.multipart;
+
+import junit.framework.TestCase;
+import org.apache.http.Header;
+import org.apache.http.util.EncodingUtils;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+
+public class MultipartTest extends TestCase {
+
+    public void testParts() throws Exception {
+        StringBuffer filebuffer = new StringBuffer();
+        String filepartStr = "this is file part";
+        filebuffer.append(filepartStr);
+        File upload = File.createTempFile("Multipart", "test");
+
+        FileWriter outFile = new FileWriter(upload);
+        BufferedWriter out = new BufferedWriter(outFile);
+        try {
+            out.write(filebuffer.toString());
+            out.flush();
+        } finally {
+            out.close();
+        }
+
+        Part[] parts = new Part[3];
+        parts[0] = new StringPart("stringpart", "PART1!!");
+        parts[1] = new FilePart(upload.getName(), upload);
+        parts[2] = new StringPart("stringpart", "PART2!!");
+
+        MultipartEntity me = new MultipartEntity(parts);
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        me.writeTo(os);
+        Header h = me.getContentType();
+        String boundry = EncodingUtils.getAsciiString(me.getMultipartBoundary());
+        StringBuffer contentType = new StringBuffer("multipart/form-data");
+        contentType.append("; boundary=");
+        contentType.append(boundry);
+        assertEquals("Multipart content type error", contentType.toString(), h.getValue());
+        final String CRLF = "\r\n";
+        StringBuffer output = new StringBuffer();
+
+        output.append("--");
+        output.append(boundry);
+        output.append(CRLF);
+
+        output.append("Content-Disposition: form-data; name=\"stringpart\"");
+        output.append(CRLF);
+        output.append("Content-Type: text/plain; charset=US-ASCII");
+        output.append(CRLF);
+        output.append("Content-Transfer-Encoding: 8bit");
+        output.append(CRLF);
+        output.append(CRLF);
+        output.append("PART1!!");
+        output.append(CRLF);
+
+        output.append("--");
+        output.append(boundry);
+        output.append(CRLF);
+
+        output.append("Content-Disposition: form-data; name=\"");
+        output.append(upload.getName());
+        output.append("\"; filename=\"");
+        output.append(upload.getName());
+        output.append("\"");
+
+        output.append(CRLF);
+        output.append("Content-Type: application/octet-stream; charset=ISO-8859-1");
+        output.append(CRLF);
+        output.append("Content-Transfer-Encoding: binary");
+        output.append(CRLF);
+        output.append(CRLF);
+        output.append(filepartStr);
+        output.append(CRLF);
+
+        output.append("--");
+        output.append(boundry);
+        output.append(CRLF);
+
+        output.append("Content-Disposition: form-data; name=\"stringpart\"");
+        output.append(CRLF);
+        output.append("Content-Type: text/plain; charset=US-ASCII");
+        output.append(CRLF);
+        output.append("Content-Transfer-Encoding: 8bit");
+        output.append(CRLF);
+        output.append(CRLF);
+        output.append("PART2!!");
+        output.append(CRLF);
+
+        output.append("--");
+        output.append(boundry);
+        output.append("--");
+        output.append(CRLF);
+        // System.out.print(output.toString());
+        assertEquals("Multipart content error", output.toString(), os.toString());
+
+        // System.out.print(os.toString());
+    }
+}
diff --git a/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java b/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java
new file mode 100644
index 0000000..8e3a034
--- /dev/null
+++ b/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2008 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.internal.os;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.io.StringWriter;
+import java.io.PrintWriter;
+
+public class LoggingPrintStreamTest extends TestCase {
+
+    TestPrintStream out = new TestPrintStream();
+
+    public void testPrintException() {
+        @SuppressWarnings("ThrowableInstanceNeverThrown")
+        Throwable t = new Throwable("Ignore me.");
+
+        StringWriter sout = new StringWriter();
+        t.printStackTrace(new PrintWriter(sout));
+
+        t.printStackTrace(out);
+        // t.printStackTrace();
+
+        String[] lines = sout.toString().split("\\n");
+        assertEquals(Arrays.asList(lines), out.lines);
+    }
+
+    public void testPrintObject() {
+        Object o = new Object();
+        out.print(4);
+        out.print(o);
+        out.print(2);
+        out.flush();
+        assertEquals(Arrays.asList("4" + o + "2"), out.lines);
+    }
+
+    public void testPrintlnObject() {
+        Object o = new Object();
+        out.print(4);
+        out.println(o);
+        out.print(2);
+        out.flush();
+        assertEquals(Arrays.asList("4" + o, "2"), out.lines);
+    }
+
+    public void testPrintf() {
+        out.printf("Name: %s\nEmployer: %s", "Bob", "Google");
+        assertEquals(Arrays.asList("Name: Bob"), out.lines);
+        out.flush();
+        assertEquals(Arrays.asList("Name: Bob", "Employer: Google"), out.lines);
+    }
+
+    public void testPrintInt() {
+        out.print(4);
+        out.print(2);
+        assertTrue(out.lines.isEmpty());
+        out.flush();
+        assertEquals(Collections.singletonList("42"), out.lines);
+    }
+
+    public void testPrintlnInt() {
+        out.println(4);
+        out.println(2);
+        assertEquals(Arrays.asList("4", "2"), out.lines);
+    }
+
+    public void testPrintCharArray() {
+        out.print("Foo\nBar\nTee".toCharArray());
+        assertEquals(Arrays.asList("Foo", "Bar"), out.lines);
+        out.flush();
+        assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
+    }
+
+    public void testPrintString() {
+        out.print("Foo\nBar\nTee");
+        assertEquals(Arrays.asList("Foo", "Bar"), out.lines);
+        out.flush();
+        assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
+    }
+
+    public void testPrintlnCharArray() {
+        out.println("Foo\nBar\nTee".toCharArray());
+        assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
+    }
+
+    public void testPrintlnString() {
+        out.println("Foo\nBar\nTee");
+        assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
+    }
+
+    public void testPrintlnStringWithBufferedData() {
+        out.print(5);
+        out.println("Foo\nBar\nTee");
+        assertEquals(Arrays.asList("5Foo", "Bar", "Tee"), out.lines);
+    }
+
+    public void testAppend() {
+        out.append("Foo\n")
+            .append('4')
+            .append('\n')
+            .append("Bar", 1, 2)
+            .append('\n');
+        assertEquals(Arrays.asList("Foo", "4", "a"), out.lines);
+    }
+
+    static class TestPrintStream extends LoggingPrintStream {
+
+        final List<String> lines = new ArrayList<String>();
+
+        protected void log(String line) {
+            lines.add(line);
+        }
+    }
+
+}
diff --git a/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java b/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java
new file mode 100644
index 0000000..0368651
--- /dev/null
+++ b/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2008 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.internal.policy.impl;
+
+import android.content.Context;
+
+import com.android.internal.telephony.SimCard;
+import android.test.AndroidTestCase;
+import android.view.View;
+import android.view.KeyEvent;
+import com.android.internal.widget.LockPatternUtils;
+import com.google.android.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Tests for {@link com.android.internal.policy.impl.LockPatternKeyguardView},
+ * which handles the management of screens while the keyguard is showing.
+ */
+public class LockPatternKeyguardViewTest extends AndroidTestCase {
+    private MockUpdateMonitor mUpdateMonitor;
+    private LockPatternUtils mLockPatternUtils;
+    private TestableLockPatternKeyguardView mLPKV;
+    private MockKeyguardCallback mKeyguardViewCallback;
+
+    private static class MockUpdateMonitor extends KeyguardUpdateMonitor {
+
+        public SimCard.State simState = SimCard.State.READY;
+        public boolean inPortrait = false;
+        public boolean keyboardOpen = false;
+
+        private MockUpdateMonitor(Context context) {
+            super(context);
+        }
+
+        @Override
+        public SimCard.State getSimState() {
+            return simState;
+        }
+
+        @Override
+        public boolean isInPortrait() {
+            return inPortrait;
+        }
+
+        @Override
+        public boolean isKeyboardOpen() {
+            return keyboardOpen;
+        }
+
+        @Override
+        boolean queryInPortrait() {
+            return inPortrait;
+        }
+
+        @Override
+        boolean queryKeyboardOpen() {
+            return keyboardOpen;
+        }
+    }
+
+    private static class MockLockPatternUtils extends LockPatternUtils {
+        boolean isLockPatternEnabled = true;
+        public boolean isPermanentlyLocked = false;
+
+        public MockLockPatternUtils() {
+            super(null);
+        }
+
+        @Override
+        public boolean isLockPatternEnabled() {
+            return isLockPatternEnabled;
+        }
+
+        @Override
+        public void setLockPatternEnabled(boolean lockPatternEnabled) {
+            isLockPatternEnabled = lockPatternEnabled;
+        }
+
+        @Override
+        public boolean isPermanentlyLocked() {
+            return isPermanentlyLocked;
+        }
+
+        public void setPermanentlyLocked(boolean permanentlyLocked) {
+            isPermanentlyLocked = permanentlyLocked;
+        }
+    }
+
+    private static class MockKeyguardScreen extends View implements KeyguardScreen {
+
+        private int mOnPauseCount = 0;
+        private int mOnResumeCount = 0;
+        private int mCleanupCount = 0;
+
+        private MockKeyguardScreen(Context context) {
+            super(context);
+            setFocusable(true);
+        }
+
+        /** {@inheritDoc} */
+        public boolean needsInput() {
+            return false;
+        }
+        
+        /** {@inheritDoc} */
+        public void onPause() {
+            mOnPauseCount++;
+        }
+
+        /** {@inheritDoc} */
+        public void onResume() {
+            mOnResumeCount++;
+        }
+
+        /** {@inheritDoc} */
+        public void cleanUp() {
+            mCleanupCount++;
+        }
+
+        public int getOnPauseCount() {
+            return mOnPauseCount;
+        }
+
+        public int getOnResumeCount() {
+            return mOnResumeCount;
+        }
+
+        public int getCleanupCount() {
+            return mCleanupCount;
+        }
+    }
+
+    /**
+     * Allows us to inject the lock and unlock views to simulate their behavior
+     * and detect their creation.
+     */
+    private static class TestableLockPatternKeyguardView extends LockPatternKeyguardView {
+        private List<MockKeyguardScreen> mInjectedLockScreens;
+        private List<MockKeyguardScreen> mInjectedUnlockScreens;
+
+
+
+        private TestableLockPatternKeyguardView(Context context, KeyguardUpdateMonitor updateMonitor,
+                LockPatternUtils lockPatternUtils, KeyguardWindowController controller) {
+            super(context, updateMonitor, lockPatternUtils, controller);
+        }
+
+        @Override
+        View createLockScreen() {
+            final MockKeyguardScreen newView = new MockKeyguardScreen(getContext());
+            if (mInjectedLockScreens == null) mInjectedLockScreens = Lists.newArrayList();
+            mInjectedLockScreens.add(newView);
+            return newView;
+        }
+
+        @Override
+        View createUnlockScreenFor(UnlockMode unlockMode) {
+            final MockKeyguardScreen newView = new MockKeyguardScreen(getContext());
+            if (mInjectedUnlockScreens == null)  mInjectedUnlockScreens = Lists.newArrayList();
+            mInjectedUnlockScreens.add(newView);
+            return newView;
+        }
+
+        public List<MockKeyguardScreen> getInjectedLockScreens() {
+            return mInjectedLockScreens;
+        }
+
+        public List<MockKeyguardScreen> getInjectedUnlockScreens() {
+            return mInjectedUnlockScreens;
+        }
+    }
+
+    private static class MockKeyguardCallback implements KeyguardViewCallback {
+
+        private int mPokeWakelockCount = 0;
+        private int mKeyguardDoneCount = 0;
+
+        public void pokeWakelock() {
+            mPokeWakelockCount++;
+        }
+
+        public void pokeWakelock(int millis) {
+            mPokeWakelockCount++;
+        }
+
+        public void keyguardDone(boolean authenticated) {
+            mKeyguardDoneCount++;
+        }
+
+        public void keyguardDoneDrawing() {
+            
+        }
+
+        public int getPokeWakelockCount() {
+            return mPokeWakelockCount;
+        }
+
+        public int getKeyguardDoneCount() {
+            return mKeyguardDoneCount;
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mUpdateMonitor = new MockUpdateMonitor(getContext());
+        mLockPatternUtils = new MockLockPatternUtils();
+
+        mLPKV = new TestableLockPatternKeyguardView(getContext(), mUpdateMonitor,
+                mLockPatternUtils, new KeyguardWindowController() {
+            public void setNeedsInput(boolean needsInput) {
+            }
+        });
+        mKeyguardViewCallback = new MockKeyguardCallback();
+        mLPKV.setCallback(mKeyguardViewCallback);
+    }
+
+    public void testStateAfterCreatedWhileScreenOff() {
+
+        assertEquals(1, mLPKV.getInjectedLockScreens().size());
+        assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+
+        MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+        MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+        assertEquals(0, lockScreen.getOnPauseCount());
+        assertEquals(0, lockScreen.getOnResumeCount());
+        assertEquals(0, lockScreen.getCleanupCount());
+
+        assertEquals(0, unlockScreen.getOnPauseCount());
+        assertEquals(0, unlockScreen.getOnResumeCount());
+        assertEquals(0, unlockScreen.getCleanupCount());
+
+        assertEquals(0, mKeyguardViewCallback.getPokeWakelockCount());
+        assertEquals(0, mKeyguardViewCallback.getKeyguardDoneCount());
+    }
+
+    public void testWokenByNonMenuKey() {
+        mLPKV.wakeWhenReadyTq(0);
+
+        // should have poked the wakelock to turn on the screen
+        assertEquals(1, mKeyguardViewCallback.getPokeWakelockCount());
+
+        // shouldn't be any additional views created
+        assertEquals(1, mLPKV.getInjectedLockScreens().size());
+        assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+        MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+        MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+        // lock screen should be only visible one
+        assertEquals(View.VISIBLE, lockScreen.getVisibility());
+        assertEquals(View.GONE, unlockScreen.getVisibility());
+
+        // on resume not called until screen turns on
+        assertEquals(0, lockScreen.getOnPauseCount());
+        assertEquals(0, lockScreen.getOnResumeCount());
+        assertEquals(0, lockScreen.getCleanupCount());
+
+        assertEquals(0, unlockScreen.getOnPauseCount());
+        assertEquals(0, unlockScreen.getOnResumeCount());
+        assertEquals(0, unlockScreen.getCleanupCount());
+
+        // simulate screen turning on
+        mLPKV.onScreenTurnedOn();
+
+        assertEquals(0, lockScreen.getOnPauseCount());
+        assertEquals(1, lockScreen.getOnResumeCount());
+        assertEquals(0, lockScreen.getCleanupCount());
+
+        assertEquals(0, unlockScreen.getOnPauseCount());
+        assertEquals(0, unlockScreen.getOnResumeCount());
+        assertEquals(0, unlockScreen.getCleanupCount());
+    }
+
+    public void testWokenByMenuKeyWhenPatternSet() {
+        assertEquals(true, mLockPatternUtils.isLockPatternEnabled());
+
+        mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU);
+
+        // should have poked the wakelock to turn on the screen
+        assertEquals(1, mKeyguardViewCallback.getPokeWakelockCount());
+        
+        // shouldn't be any additional views created
+        assertEquals(1, mLPKV.getInjectedLockScreens().size());
+        assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+        MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+        MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+        // unlock screen should be only visible one
+        assertEquals(View.GONE, lockScreen.getVisibility());
+        assertEquals(View.VISIBLE, unlockScreen.getVisibility());
+    }
+
+    public void testScreenRequestsRecreation() {
+        mLPKV.wakeWhenReadyTq(0);
+        mLPKV.onScreenTurnedOn();
+
+        assertEquals(1, mLPKV.getInjectedLockScreens().size());
+        assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+        MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+
+        assertEquals(0, lockScreen.getOnPauseCount());
+        assertEquals(1, lockScreen.getOnResumeCount());
+
+        // simulate screen asking to be recreated
+        mLPKV.mKeyguardScreenCallback.recreateMe();
+
+        // should have been recreated
+        assertEquals(2, mLPKV.getInjectedLockScreens().size());
+        assertEquals(2, mLPKV.getInjectedUnlockScreens().size());
+
+        // both old screens should have been cleaned up
+        assertEquals(1, mLPKV.getInjectedLockScreens().get(0).getCleanupCount());
+        assertEquals(1, mLPKV.getInjectedUnlockScreens().get(0).getCleanupCount());
+
+        // old lock screen should have been paused
+        assertEquals(1, mLPKV.getInjectedLockScreens().get(0).getOnPauseCount());
+        assertEquals(0, mLPKV.getInjectedUnlockScreens().get(0).getOnPauseCount());
+
+        // new lock screen should have been resumed
+        assertEquals(1, mLPKV.getInjectedLockScreens().get(1).getOnResumeCount());
+        assertEquals(0, mLPKV.getInjectedUnlockScreens().get(1).getOnResumeCount());
+    }
+
+    public void testMenuDoesntGoToUnlockScreenOnWakeWhenPukLocked() {
+        // PUK locked
+        mUpdateMonitor.simState = SimCard.State.PUK_REQUIRED;
+
+        // wake by menu
+        mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU);
+
+        assertEquals(1, mLPKV.getInjectedLockScreens().size());
+        assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+        MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+        MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+        // lock screen should be only visible one
+        assertEquals(View.VISIBLE, lockScreen.getVisibility());
+        assertEquals(View.GONE, unlockScreen.getVisibility());
+    }
+
+    public void testMenuGoesToLockScreenWhenDeviceNotSecure() {
+        mLockPatternUtils.setLockPatternEnabled(false);
+
+        // wake by menu
+        mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU);
+
+        assertEquals(1, mLPKV.getInjectedLockScreens().size());
+        assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+        MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+        MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+        // lock screen should be only visible one
+        assertEquals(View.VISIBLE, lockScreen.getVisibility());
+        assertEquals(View.GONE, unlockScreen.getVisibility());
+    }
+}
diff --git a/tests/gadgets/GadgetHostTest/Android.mk b/tests/gadgets/GadgetHostTest/Android.mk
new file mode 100644
index 0000000..5e04b81
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GadgetHostTest
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/gadgets/GadgetHostTest/AndroidManifest.xml b/tests/gadgets/GadgetHostTest/AndroidManifest.xml
new file mode 100644
index 0000000..52e314f
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.tests.gadgethost">
+    <uses-permission android:name="android.permission.VIBRATE" />
+
+    <application>
+        <activity android:name="GadgetHostActivity" android:label="_GadgetHost">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="TestGadgetConfigure" android:label="Configure TestGadgetProvider">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- BEGIN_INCLUDE(GadgetProvider) -->
+        <receiver android:name="TestGadgetProvider"
+                    android:label="@string/oh_hai"
+                    android:icon="@drawable/oh_hai_icon"
+                    >
+            <intent-filter>
+                <action android:name="android.gadget.action.GADGET_UPDATE" />
+            </intent-filter>
+            <meta-data android:name="android.gadget.provider"
+                        android:resource="@xml/gadget_info"
+                        />
+        </receiver>
+        <!-- END_INCLUDE(GadgetProvider) -->
+        
+    </application>
+</manifest>
diff --git a/tests/gadgets/GadgetHostTest/res/drawable/oh_hai_icon.png b/tests/gadgets/GadgetHostTest/res/drawable/oh_hai_icon.png
new file mode 100644
index 0000000..30ff267
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/drawable/oh_hai_icon.png
Binary files differ
diff --git a/tests/gadgets/GadgetHostTest/res/layout/gadget_host.xml b/tests/gadgets/GadgetHostTest/res/layout/gadget_host.xml
new file mode 100644
index 0000000..743f6c6
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/layout/gadget_host.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/gadget_view_title"
+    />
+
+    <ScrollView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        >
+        
+        <com.android.tests.gadgethost.GadgetContainerView
+            android:id="@+id/gadget_container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+        />
+
+    </ScrollView>
+
+    <Button
+        android:id="@+id/add_gadget"
+        android:text="@string/add_gadget"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        />
+
+</LinearLayout>
+
diff --git a/tests/gadgets/GadgetHostTest/res/layout/test_gadget.xml b/tests/gadgets/GadgetHostTest/res/layout/test_gadget.xml
new file mode 100644
index 0000000..4d483c7
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/layout/test_gadget.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/oh_hai_text"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="@string/oh_hai"
+/>
+
diff --git a/tests/gadgets/GadgetHostTest/res/layout/test_gadget_configure.xml b/tests/gadgets/GadgetHostTest/res/layout/test_gadget_configure.xml
new file mode 100644
index 0000000..0d9b983
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/layout/test_gadget_configure.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    >
+
+    <TextView
+        android:id="@+id/oh_hai_text"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/oh_hai"
+    />
+
+    <EditText
+        android:id="@+id/edit_text"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+    />
+
+    <Button
+        android:id="@+id/save_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/save"
+    />
+
+
+</LinearLayout>
diff --git a/tests/gadgets/GadgetHostTest/res/values/strings.xml b/tests/gadgets/GadgetHostTest/res/values/strings.xml
new file mode 100644
index 0000000..ad9916a
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="gadget_view_title">Gadget Test</string>
+    <string name="add_gadget">Add Gadget</string>
+    <string name="oh_hai">Oh hai.</string>
+    <string name="delete_gadget">Delete</string>
+    <string name="save">Save</string>
+</resources>
+
diff --git a/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml b/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml
new file mode 100644
index 0000000..e0c4222
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml
@@ -0,0 +1,10 @@
+<!-- BEGIN_INCLUDE(GadgetProviderInfo) -->
+<gadget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+    android:minWidth="40dp"
+    android:minHeight="30dp"
+    android:updatePeriodMillis="86400000"
+    android:initialLayout="@layout/test_gadget"
+    android:configure="com.android.tests.gadgethost.TestGadgetConfigure"
+    >
+</gadget-provider>
+<!-- END_INCLUDE(GadgetProviderInfo) -->
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetContainerView.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetContainerView.java
new file mode 100644
index 0000000..3814836
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetContainerView.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 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.tests.gadgethost;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+public class GadgetContainerView extends LinearLayout
+{
+    public GadgetContainerView(Context context) {
+        super(context);
+    }
+
+    public GadgetContainerView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+}
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java
new file mode 100644
index 0000000..0bd8926
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008 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.tests.gadgethost;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.gadget.GadgetHost;
+import android.gadget.GadgetHostView;
+import android.gadget.GadgetProviderInfo;
+import android.gadget.GadgetManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.LinearLayout;
+
+public class GadgetHostActivity extends Activity
+{
+    static final String TAG = "GadgetHostActivity";
+
+    static final int DISCOVER_GADGET_REQUEST = 1;
+    static final int CONFIGURE_GADGET_REQUEST = 2;
+    static final int HOST_ID = 1234;
+
+    static final String PENDING_GADGET_ID = "pending_gadget";
+    
+    GadgetManager mGadgetManager;
+    GadgetContainerView mGadgetContainer;
+
+    public GadgetHostActivity() {
+        mGadgetManager = GadgetManager.getInstance(this);
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.gadget_host);
+
+        findViewById(R.id.add_gadget).setOnClickListener(mOnClickListener);
+        mGadgetContainer = (GadgetContainerView)findViewById(R.id.gadget_container);
+
+        if (false) {
+            if (false) {
+                mHost.deleteHost();
+            } else {
+                GadgetHost.deleteAllHosts();
+            }
+        }
+    }
+
+    View.OnClickListener mOnClickListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            discoverGadget(DISCOVER_GADGET_REQUEST);
+        }
+    };
+
+    void discoverGadget(int requestCode) {
+        Intent intent = new Intent(GadgetManager.ACTION_GADGET_PICK);
+        intent.putExtra(GadgetManager.EXTRA_GADGET_ID, mHost.allocateGadgetId());
+        startActivityForResult(intent, requestCode);
+    }
+
+    void configureGadget(int requestCode, int gadgetId, ComponentName configure) {
+        Intent intent = new Intent(GadgetManager.ACTION_GADGET_CONFIGURE);
+        intent.setComponent(configure);
+        intent.putExtra(GadgetManager.EXTRA_GADGET_ID, gadgetId);
+        SharedPreferences.Editor prefs = getPreferences(0).edit();
+        prefs.putInt(PENDING_GADGET_ID, gadgetId);
+        prefs.commit();
+        startActivityForResult(intent, requestCode);
+    }
+
+    void handleGadgetPickResult(int resultCode, Intent intent) {
+        // BEGIN_INCLUDE(getExtra_EXTRA_GADGET_ID)
+        Bundle extras = intent.getExtras();
+        int gadgetId = extras.getInt(GadgetManager.EXTRA_GADGET_ID);
+        // END_INCLUDE(getExtra_EXTRA_GADGET_ID)
+        if (resultCode == RESULT_OK) {
+            GadgetProviderInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
+
+            if (gadget.configure != null) {
+                // configure the gadget if we should
+                configureGadget(CONFIGURE_GADGET_REQUEST, gadgetId, gadget.configure);
+            } else {
+                // just add it as is
+                addGadgetView(gadgetId, gadget);
+            }
+        } else {
+            mHost.deleteGadgetId(gadgetId);
+        }
+    }
+
+    void handleGadgetConfigureResult(int resultCode, Intent data) {
+        int gadgetId = getPreferences(0).getInt(PENDING_GADGET_ID, -1);
+        Log.d(TAG, "resultCode=" + resultCode + " gadgetId=" + gadgetId);
+        if (gadgetId < 0) {
+            Log.w(TAG, "was no preference for PENDING_GADGET_ID");
+            return;
+        }
+        if (resultCode == RESULT_OK) {
+            GadgetProviderInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
+            addGadgetView(gadgetId, gadget);
+        } else {
+            mHost.deleteGadgetId(gadgetId);
+        }
+    }
+
+    void addGadgetView(int gadgetId, GadgetProviderInfo gadget) {
+        // Inflate the gadget's RemoteViews
+        GadgetHostView view = mHost.createView(this, gadgetId, gadget);
+
+        // Add it to the list
+        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.FILL_PARENT,
+                LinearLayout.LayoutParams.WRAP_CONTENT);
+        mGadgetContainer.addView(view, layoutParams);
+
+        registerForContextMenu(view);
+    }
+
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        switch (requestCode) {
+        case DISCOVER_GADGET_REQUEST:
+            handleGadgetPickResult(resultCode, data);
+            break;
+        case CONFIGURE_GADGET_REQUEST:
+            handleGadgetConfigureResult(resultCode, data);
+        }
+    }
+
+    protected void onStart() {
+        super.onStart();
+        mHost.startListening();
+    }
+
+    protected void onStop() {
+        super.onStop();
+        mHost.stopListening();
+    }
+
+    public void onCreateContextMenu(ContextMenu menu, View v,
+            ContextMenu.ContextMenuInfo menuInfo) {
+        menu.add(ContextMenu.NONE, R.string.delete_gadget, ContextMenu.NONE,
+                R.string.delete_gadget);
+    }
+
+    public boolean onContextItemSelected(MenuItem item) {
+        MyGadgetView view = (MyGadgetView)item.getMenuInfo();
+        switch (item.getItemId()) {
+        case R.string.delete_gadget:
+            Log.d(TAG, "delete! " + view.gadgetId);
+            mGadgetContainer.removeView(view);
+            mHost.deleteGadgetId(view.gadgetId);
+            break;
+        }
+
+        return true;
+    }
+
+    class MyGadgetView extends GadgetHostView implements ContextMenu.ContextMenuInfo {
+        int gadgetId;
+
+        MyGadgetView(int gadgetId) {
+            super(GadgetHostActivity.this);
+            this.gadgetId = gadgetId;
+        }
+
+        public ContextMenu.ContextMenuInfo getContextMenuInfo() {
+            return this;
+        }
+    }
+
+    GadgetHost mHost = new GadgetHost(this, HOST_ID) {
+        protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetProviderInfo gadget) {
+            return new MyGadgetView(gadgetId);
+        }
+    };
+}
+
+
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetConfigure.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetConfigure.java
new file mode 100644
index 0000000..897c13c
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetConfigure.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 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.tests.gadgethost;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.EditText;
+
+public class TestGadgetConfigure extends Activity {
+    static final String TAG = "TestGadgetConfigure";
+
+    public TestGadgetConfigure() {
+        super();
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.test_gadget_configure);
+
+        findViewById(R.id.save_button).setOnClickListener(mOnClickListener);
+    }
+
+    View.OnClickListener mOnClickListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            String text = ((EditText)findViewById(R.id.edit_text)).getText().toString();
+            Log.d(TAG, "text is '" + text + '\'');
+            SharedPreferences.Editor prefs = getSharedPreferences(TestGadgetProvider.PREFS_NAME, 0)
+                    .edit();
+            prefs.putString(TestGadgetProvider.PREF_PREFIX_KEY, text);
+            prefs.commit();
+            setResult(RESULT_OK);
+            finish();
+        }
+    };
+
+}
+
+
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java
new file mode 100644
index 0000000..370a50b
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 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.tests.gadgethost;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.gadget.GadgetManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+public class TestGadgetProvider extends BroadcastReceiver {
+    static final String TAG = "TestGadgetProvider";
+
+    static final String PREFS_NAME = "com.android.tests.gadgethost.TestGadgetProvider";
+    static final String PREF_PREFIX_KEY = "prefix";
+
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        Log.d(TAG, "intent=" + intent);
+
+        if (GadgetManager.ACTION_GADGET_ENABLED.equals(action)) {
+            Log.d(TAG, "ENABLED");
+        }
+        else if (GadgetManager.ACTION_GADGET_DISABLED.equals(action)) {
+            Log.d(TAG, "DISABLED");
+        }
+        else if (GadgetManager.ACTION_GADGET_UPDATE.equals(action)) {
+            Log.d(TAG, "UPDATE");
+            // BEGIN_INCLUDE(getExtra_EXTRA_GADGET_IDS)
+            Bundle extras = intent.getExtras();
+            int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
+            // END_INCLUDE(getExtra_EXTRA_GADGET_IDS)
+
+            SharedPreferences prefs = context.getSharedPreferences(
+                    TestGadgetProvider.PREFS_NAME, 0);
+            String prefix = prefs.getString(PREF_PREFIX_KEY, "hai");
+
+            GadgetManager gm = GadgetManager.getInstance(context);
+            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.test_gadget);
+            views.setTextViewText(R.id.oh_hai_text, prefix + ": " + SystemClock.elapsedRealtime());
+            if (false) {
+                gm.updateGadget(gadgetIds, views);
+            } else {
+                gm.updateGadget(new ComponentName("com.android.tests.gadgethost",
+                            "com.android.tests.gadgethost.TestGadgetProvider"), views);
+            }
+        }
+    }
+}
+
diff --git a/tests/gadgets/GadgetProviderTest/Android.mk b/tests/gadgets/GadgetProviderTest/Android.mk
new file mode 100644
index 0000000..b9bfcdb
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GadgetProvider
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/gadgets/GadgetProviderTest/AndroidManifest.xml b/tests/gadgets/GadgetProviderTest/AndroidManifest.xml
new file mode 100644
index 0000000..47a7a2e
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.tests.gadgetprovider">
+    <uses-permission android:name="android.permission.VIBRATE" />
+
+    <application>
+        <receiver android:name="TestGadgetProvider">
+            <intent-filter>
+                <action android:name="android.gadget.action.GADGET_UPDATE" />
+            </intent-filter>
+            <meta-data android:name="android.gadget.provider" android:resource="@xml/gadget_info" />
+        </receiver>
+    </application>
+</manifest>
diff --git a/tests/gadgets/GadgetProviderTest/res/layout/test_gadget.xml b/tests/gadgets/GadgetProviderTest/res/layout/test_gadget.xml
new file mode 100644
index 0000000..e0a416e
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/res/layout/test_gadget.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/oh_hai_text"
+    android:layout_width="150dp"
+    android:layout_height="150dp"
+    android:text="@string/oh_hai"
+    android:background="#8fff"
+    android:textColor="#000"
+    android:textStyle="bold"
+/>
+
diff --git a/tests/gadgets/GadgetProviderTest/res/values/strings.xml b/tests/gadgets/GadgetProviderTest/res/values/strings.xml
new file mode 100644
index 0000000..e07725f
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="gadget_view_title">Gadget Test</string>
+    <string name="add_gadget">Add Gadget</string>
+    <string name="oh_hai">Oh hai.</string>
+    <string name="delete_gadget">Delete</string>
+</resources>
+
diff --git a/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml b/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml
new file mode 100644
index 0000000..33cc2e3
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml
@@ -0,0 +1,7 @@
+<gadget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+    android:minWidth="150dp"
+    android:minHeight="150dp"
+    android:updatePeriodMillis="2000"
+    android:initialLayout="@layout/test_gadget"
+    >
+</gadget-provider>
diff --git a/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java b/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java
new file mode 100644
index 0000000..b81575f
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 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.tests.gadgetprovider;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.gadget.GadgetManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+public class TestGadgetProvider extends BroadcastReceiver {
+
+    static final String TAG = "TestGadgetProvider";
+
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        Log.d(TAG, "intent=" + intent);
+
+        if (GadgetManager.ACTION_GADGET_ENABLED.equals(action)) {
+            Log.d(TAG, "ENABLED");
+        }
+        else if (GadgetManager.ACTION_GADGET_DISABLED.equals(action)) {
+            Log.d(TAG, "DISABLED");
+        }
+        else if (GadgetManager.ACTION_GADGET_UPDATE.equals(action)) {
+            Log.d(TAG, "UPDATE");
+            Bundle extras = intent.getExtras();
+            int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
+
+            GadgetManager gm = GadgetManager.getInstance(context);
+            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.test_gadget);
+            views.setTextViewText(R.id.oh_hai_text, "hai: " + SystemClock.elapsedRealtime());
+            if (false) {
+                gm.updateGadget(gadgetIds, views);
+            } else {
+                gm.updateGadget(new ComponentName("com.android.tests.gadgetprovider",
+                            "com.android.tests.gadgetprovider.TestGadgetProvider"), views);
+            }
+        }
+    }
+}
+