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..e5a78bc
--- /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();
+        }
+    }
+}